Class MCollective::Security::Base
In: lib/mcollective/security/base.rb
Parent: Object

This is a base class the other security modules should inherit from it handles statistics and validation of messages that should in most cases apply to all security models.

To create your own security plugin you should provide a plugin that inherits from this and provides the following methods:

decodemsg - Decodes a message that was received from the middleware encodereply - Encodes a reply message to a previous request message encoderequest - Encodes a new request message validrequest? - Validates a request received from the middleware

Optionally if you are identifying users by some other means like certificate name you can provide your own callerid method that can provide the rest of the system with an id, and you would see this id being usable in SimpleRPC authorization methods

The @initiated_by variable will be set to either :client or :node depending on who is using this plugin. This is to help security providers that operate in an asymetric mode like public/private key based systems.

Specifics of each of these are a bit fluid and the interfaces for this is not set in stone yet, specifically the encode methods will be provided with a helper that takes care of encoding the core requirements. The best place to see how security works is by looking at the provided MCollective::Security::PSK plugin.

Methods

Attributes

initiated_by  [RW] 
stats  [R] 

Public Class methods

Register plugins that inherits base

[Source]

    # File lib/mcollective/security/base.rb, line 32
32:             def self.inherited(klass)
33:                 PluginManager << {:type => "security_plugin", :class => klass.to_s}
34:             end

Initializes configuration and logging as well as prepare a zero‘d hash of stats various security methods and filter validators should increment stats, see MCollective::Security::Psk for a sample

[Source]

    # File lib/mcollective/security/base.rb, line 38
38:             def initialize
39:                 @config = Config.instance
40:                 @log = Log
41:                 @stats = PluginManager["global_stats"]
42:             end

Public Instance methods

Returns a unique id for the caller, by default we just use the unix user id, security plugins can provide their own means of doing ids.

[Source]

     # File lib/mcollective/security/base.rb, line 160
160:             def callerid
161:                 "uid=#{Process.uid}"
162:             end

[Source]

     # File lib/mcollective/security/base.rb, line 125
125:             def create_reply(reqid, agent, target, body)
126:                 Log.debug("Encoded a message for request #{reqid}")
127: 
128:                 {:senderid => @config.identity,
129:                  :requestid => reqid,
130:                  :senderagent => agent,
131:                  :msgtarget => target,
132:                  :msgtime => Time.now.to_i,
133:                  :body => body}
134:             end

[Source]

     # File lib/mcollective/security/base.rb, line 136
136:             def create_request(reqid, target, filter, msg, initiated_by, target_agent=nil, target_collective=nil)
137:                 Log.debug("Encoding a request for '#{target}' with request id #{reqid}")
138: 
139:                 # for backward compat with <= 1.1.4 security plugins we parse the
140:                 # msgtarget to figure out the agent and collective
141:                 unless target_agent && target_collective
142:                     parsed_target = Util.parse_msgtarget(target)
143:                     target_agent = parsed_target[:agent]
144:                     target_collective = parsed_target[:collective]
145:                 end
146: 
147:                 {:body => msg,
148:                  :senderid => @config.identity,
149:                  :requestid => reqid,
150:                  :msgtarget => target,
151:                  :filter => filter,
152:                  :collective => target_collective,
153:                  :agent => target_agent,
154:                  :callerid => callerid,
155:                  :msgtime => Time.now.to_i}
156:             end

Security providers should provide this, see MCollective::Security::Psk

[Source]

     # File lib/mcollective/security/base.rb, line 180
180:             def decodemsg(msg)
181:                 Log.error("decodemsg is not implimented in #{self.class}")
182:             end

Security providers should provide this, see MCollective::Security::Psk

[Source]

     # File lib/mcollective/security/base.rb, line 175
175:             def encodereply(sender, target, msg, requestcallerid=nil)
176:                 Log.error("encodereply is not implimented in #{self.class}")
177:             end

Security providers should provide this, see MCollective::Security::Psk

[Source]

     # File lib/mcollective/security/base.rb, line 170
170:             def encoderequest(sender, target, msg, filter={})
171:                 Log.error("encoderequest is not implimented in #{self.class}")
172:             end

Takes a Hash with a filter in it and validates it against host information.

At present this supports filter matches against the following criteria:

  • puppet_class|cf_class - Presence of a configuration management class in
                            the file configured with classesfile
    
  • agent - Presence of a MCollective agent with a supplied name
  • fact - The value of a fact avout this system
  • identity - the configured identity of the system

TODO: Support REGEX and/or multiple filter keys to be AND‘d

[Source]

     # File lib/mcollective/security/base.rb, line 55
 55:             def validate_filter?(filter)
 56:                 failed = 0
 57:                 passed = 0
 58: 
 59:                 passed = 1 if Util.empty_filter?(filter)
 60: 
 61:                 filter.keys.each do |key|
 62:                     case key
 63:                         when /puppet_class|cf_class/
 64:                             filter[key].each do |f|
 65:                                 Log.debug("Checking for class #{f}")
 66:                                 if Util.has_cf_class?(f) then
 67:                                     Log.debug("Passing based on configuration management class #{f}")
 68:                                     passed += 1
 69:                                 else
 70:                                     Log.debug("Failing based on configuration management class #{f}")
 71:                                     failed += 1
 72:                                 end
 73:                             end
 74: 
 75:                         when "agent"
 76:                             filter[key].each do |f|
 77:                                 if Util.has_agent?(f) || f == "mcollective"
 78:                                     Log.debug("Passing based on agent #{f}")
 79:                                     passed += 1
 80:                                 else
 81:                                     Log.debug("Failing based on agent #{f}")
 82:                                     failed += 1
 83:                                 end
 84:                             end
 85: 
 86:                         when "fact"
 87:                             filter[key].each do |f|
 88:                                 if Util.has_fact?(f[:fact], f[:value], f[:operator])
 89:                                     Log.debug("Passing based on fact #{f[:fact]} #{f[:operator]} #{f[:value]}")
 90:                                     passed += 1
 91:                                 else
 92:                                     Log.debug("Failing based on fact #{f[:fact]} #{f[:operator]} #{f[:value]}")
 93:                                     failed += 1
 94:                                 end
 95:                             end
 96: 
 97:                         when "identity"
 98:                             filter[key].each do |f|
 99:                                 if Util.has_identity?(f)
100:                                     Log.debug("Passing based on identity = #{f}")
101:                                     passed += 1
102:                                 else
103:                                     Log.debug("Failed based on identity = #{f}")
104:                                     failed += 1
105:                                 end
106:                             end
107:                     end
108:                 end
109: 
110:                 if failed == 0 && passed > 0
111:                     Log.debug("Message passed the filter checks")
112: 
113:                     @stats.passed
114: 
115:                     return true
116:                 else
117:                     Log.debug("Message failed the filter checks")
118: 
119:                     @stats.filtered
120: 
121:                     return false
122:                 end
123:             end

Security providers should provide this, see MCollective::Security::Psk

[Source]

     # File lib/mcollective/security/base.rb, line 165
165:             def validrequest?(req)
166:                 Log.error("validrequest? is not implimented in #{self.class}")
167:             end

[Validate]