Class: Cisco::SnmpUser

Inherits:
NodeUtil show all
Defined in:
lib/cisco_node_utils/snmpuser.rb

Overview

SnmpUser - node utility class for SNMP user configuration management

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from NodeUtil

client, #client, config_get, #config_get, #config_get_default, config_get_default, config_set, #config_set, #get, #ios_xr?, #nexus?, #node, node, platform, #platform, supports?, #supports?

Constructor Details

#initialize(name, groups, authproto, authpass, privproto, privpass, localizedkey, engineid, instantiate = true) ⇒ SnmpUser

Returns a new instance of SnmpUser.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/cisco_node_utils/snmpuser.rb', line 20

def initialize(name, groups, authproto, authpass, privproto,
               privpass, localizedkey, engineid, instantiate=true)
  initialize_validator(name, groups, authproto, authpass, privproto,
                       privpass, engineid, instantiate)
  @name = name
  @engine_id = engineid

  @authproto = authproto
  @privproto = privproto
  @groups_arr = groups

  authprotostr = _auth_sym_to_str(authproto)
  privprotostr = _priv_sym_to_str(privproto)

  return unless instantiate
  # Config string syntax:
  # [no] snmp-server user <user> [group] ...
  #      [auth {md5|sha} <passwd1>
  #       [priv [aes-128] <passwd2>] [localizedkey] [engineID <id>]
  #      ]
  # Assume if multiple groups, apply all config to each
  groups = [''] if groups.empty?
  groups.each do |group|
    config_set('snmp_user', 'user', '',
               name,
               group,
               authpass.empty? ? '' : "auth #{authprotostr} #{authpass}",
               privpass.empty? ? '' : "priv #{privprotostr} #{privpass}",
               localizedkey ? 'localizedkey' : '',
               engineid.empty? ? '' : "engineID #{engineid}")
  end
end

Instance Attribute Details

#engine_idObject (readonly)

Returns the value of attribute engine_id.



206
207
208
# File 'lib/cisco_node_utils/snmpuser.rb', line 206

def engine_id
  @engine_id
end

#nameObject (readonly)

Returns the value of attribute name.



132
133
134
# File 'lib/cisco_node_utils/snmpuser.rb', line 132

def name
  @name
end

Class Method Details

.auth_password(name, engine_id) ⇒ Object



154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/cisco_node_utils/snmpuser.rb', line 154

def self.auth_password(name, engine_id)
  if engine_id.empty?
    users = config_get('snmp_user', 'auth_password')
    return nil if users.nil? || users.empty?
    users.each_entry { |user| return user[1] if user[0] == name }
  else
    users = config_get('snmp_user', 'auth_password_with_engine_id')
    return nil if users.nil? || users.empty?
    users.each_entry do |user|
      return user[1] if user[0] == name && user[2] == engine_id
    end
  end
  nil
end

.default_auth_passwordObject



150
151
152
# File 'lib/cisco_node_utils/snmpuser.rb', line 150

def self.default_auth_password
  config_get_default('snmp_user', 'auth_password')
end

.default_auth_protocolObject



146
147
148
# File 'lib/cisco_node_utils/snmpuser.rb', line 146

def self.default_auth_protocol
  _auth_str_to_sym(config_get_default('snmp_user', 'auth_protocol'))
end

.default_engine_idObject



208
209
210
# File 'lib/cisco_node_utils/snmpuser.rb', line 208

def self.default_engine_id
  config_get_default('snmp_user', 'engine_id')
end

.default_groupsObject



138
139
140
# File 'lib/cisco_node_utils/snmpuser.rb', line 138

def self.default_groups
  [config_get_default('snmp_user', 'group')]
end

.default_priv_passwordObject



202
203
204
# File 'lib/cisco_node_utils/snmpuser.rb', line 202

def self.default_priv_password
  config_get_default('snmp_user', 'priv_password')
end

.default_priv_protocolObject



198
199
200
# File 'lib/cisco_node_utils/snmpuser.rb', line 198

def self.default_priv_protocol
  _priv_str_to_sym(config_get_default('snmp_user', 'priv_protocol'))
end

.priv_password(name, engine_id) ⇒ Object



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/cisco_node_utils/snmpuser.rb', line 177

def self.priv_password(name, engine_id)
  if engine_id.empty?
    users = config_get('snmp_user', 'priv_password')
    unless users.nil? || users.empty?
      users.each_entry { |user| return user[1] if user[0] == name }
    end
  else
    users = config_get('snmp_user', 'priv_password_with_engine_id')
    unless users.nil? || users.empty?
      users.each_entry do |user|
        return user[1] if user[0] == name && user[2] == engine_id
      end
    end
  end
  nil
end

.usersObject



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/cisco_node_utils/snmpuser.rb', line 77

def self.users
  users_hash = {}
  # config_get returns hash if 1 user, array if multiple, nil if none
  users = config_get('snmp_user', 'user')
  return users_hash if users.nil?
  users.each do |user|
    # n7k has enforcepriv, use-ipv*acl, avoid them
    next if user[/(enforcePriv|use-ipv4acl|use-ipv6acl)/]
    user_var_hash = _get_snmp_user_parse(user)
    name = user_var_hash[:name]
    engineid = user_var_hash[:engineid]
    if engineid.empty?
      index = name
    else
      index = name + ' ' + engineid
    end
    auth = user_var_hash[:auth]
    priv = user_var_hash[:priv]
    groups_arr = []
    # take care of multiple groups here
    # if the name already exists in hash
    # get all the previous properties
    if users_hash.key?(index)
      groups_arr = users_hash[index].groups
      auth = users_hash[index].auth_protocol
      priv = users_hash[index].priv_protocol
    end

    # add the group to the array
    groups_arr << _get_group_arr(user_var_hash)
    users_hash[index] = SnmpUser.new(name, groups_arr.flatten, auth,
                                     '', priv, '', false,
                                     engineid,
                                     false)
  end
  users_hash
end

Instance Method Details

#auth_passwordObject



169
170
171
# File 'lib/cisco_node_utils/snmpuser.rb', line 169

def auth_password
  SnmpUser.auth_password(@name, @engine_id)
end

#auth_password_equal?(input_pw, is_localized = false) ⇒ Boolean

Passwords are hashed and so cannot be retrieved directly, but can be checked for equality. This is done by creating a fake user with the password and then comparing the hashes

Returns:

  • (Boolean)


215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/cisco_node_utils/snmpuser.rb', line 215

def auth_password_equal?(input_pw, is_localized=false)
  input_pw = input_pw.to_s unless input_pw.is_a?(String)
  # If we provide no password, and no password present, it's a match!
  return true if input_pw.empty? && auth_protocol == :none
  # If we provide no password, but a password is present, or vice versa...
  return false if input_pw.empty? || auth_protocol == :none
  # OK, we have an input password, and a password is configured
  current_pw = auth_password
  if current_pw.nil?
    fail "SNMP user #{@name} #{@engine_id} has auth #{auth_protocol} " \
         "but no password?\n" + @@node.get(command: 'show run snmp all')
  end

  if is_localized
    # In this case, the password is already hashed.
    hashed_pw = input_pw
  else
    # In this case passed in password is clear text while the running
    # config is hashed value. We need to hash the passed in clear text.

    # Create dummy user
    config_set('snmp_user', 'user', '', 'dummy_user', '',
               "auth #{_auth_sym_to_str(auth_protocol)} #{input_pw}",
               '', '',
               @engine_id.empty? ? '' : "engineID #{@engine_id}")

    # Retrieve password hashes
    hashed_pw = SnmpUser.auth_password('dummy_user', @engine_id)
    if hashed_pw.nil?
      fail "SNMP dummy user dummy_user #{@engine_id} was configured " \
           "but password is missing?\n" \
           + @@node.get(command: 'show run snmp all')
    end

    # Delete dummy user
    config_set('snmp_user', 'user', 'no', 'dummy_user', '',
               "auth #{_auth_sym_to_str(auth_protocol)} #{hashed_pw}",
               '', 'localizedkey',
               @engine_id.empty? ? '' : "engineID #{@engine_id}")
  end
  hashed_pw == current_pw
end

#auth_protocolObject



142
143
144
# File 'lib/cisco_node_utils/snmpuser.rb', line 142

def auth_protocol
  @authproto
end

#destroyObject



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/cisco_node_utils/snmpuser.rb', line 115

def destroy
  # The parser doesn't care what the real value is but need to come to the
  # end of the parser chain. Hence we just pass in some fake values for
  # auth method and password
  unless auth_password.nil? || auth_password.empty?
    auth_str = "auth #{_auth_sym_to_str(auth_protocol)} #{auth_password}"
    local_str = 'localizedkey'
  end
  unless priv_password.nil? || priv_password.empty?
    priv_str = "priv #{_priv_sym_to_str(priv_protocol)} #{priv_password}"
  end
  config_set('snmp_user', 'user', 'no',
             @name, '', auth_str, priv_str, local_str,
             @engine_id.empty? ? '' : "engineID #{@engine_id}")
  SnmpUser.users.delete(@name + ' ' + @engine_id)
end

#groupsObject



134
135
136
# File 'lib/cisco_node_utils/snmpuser.rb', line 134

def groups
  @groups_arr
end

#initialize_validator(name, groups, authproto, authpass, privproto, privpass, engineid, instantiate) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/cisco_node_utils/snmpuser.rb', line 53

def initialize_validator(name, groups, authproto, authpass, privproto,
                         privpass, engineid, instantiate)
  fail TypeError unless name.is_a?(String) &&
                        groups.is_a?(Array) &&
                        authproto.is_a?(Symbol) &&
                        authpass.is_a?(String) &&
                        privproto.is_a?(Symbol) &&
                        privpass.is_a?(String) &&
                        engineid.is_a?(String)
  fail ArgumentError if name.empty?
  # empty password but protocol provided = bad
  # non-empty password and no protocol provided = bad
  if authpass.empty?
    fail ArgumentError if [:sha, :md5].include?(authproto) && instantiate
  else
    fail ArgumentError unless [:sha, :md5].include?(authproto)
  end
  if privpass.empty?
    fail ArgumentError if [:des, :aes128].include?(privproto) && instantiate
  else
    fail ArgumentError unless [:des, :aes128].include?(privproto)
  end
end

#priv_passwordObject



194
195
196
# File 'lib/cisco_node_utils/snmpuser.rb', line 194

def priv_password
  SnmpUser.priv_password(@name, @engine_id)
end

#priv_password_equal?(input_pw, is_localized = false) ⇒ Boolean

Passwords are hashed and so cannot be retrieved directly, but can be checked for equality. This is done by creating a fake user with the password and then comparing the hashes

Returns:

  • (Boolean)


261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/cisco_node_utils/snmpuser.rb', line 261

def priv_password_equal?(input_pw, is_localized=false)
  input_pw = input_pw.to_s unless input_pw.is_a?(String)
  # If no input password, and no password present, true!
  return true if input_pw.empty? && priv_protocol == :none
  # Otherwise, if either one is missing, false!
  return false if input_pw.empty? || priv_protocol == :none
  # Otherwise, we have both input and configured passwords to compare
  current_pw = priv_password
  if current_pw.nil?
    fail "SNMP user #{@name} #{@engine_id} has priv #{priv_protocol} " \
         "but no password?\n" + @@node.get(command: 'show run snmp all')
  end

  if is_localized
    # In this case, the password is already hashed.
    hashed_pw = input_pw
  else
    # In this case passed in password is clear text while the running
    # config is hashed value. We need to hash the passed in clear text.

    # Create dummy user
    config_set('snmp_user', 'user', '', 'dummy_user', '',
               "auth #{_auth_sym_to_str(auth_protocol)} #{input_pw}",
               "priv #{_priv_sym_to_str(priv_protocol)} #{input_pw}",
               '',
               @engine_id.empty? ? '' : "engineID #{@engine_id}")

    # Retrieve password hashes
    dummyau = SnmpUser.auth_password('dummy_user', @engine_id)
    hashed_pw = SnmpUser.priv_password('dummy_user', @engine_id)
    if hashed_pw.nil?
      fail "SNMP dummy user dummy_user #{@engine_id} was configured " \
           "but password is missing?\n" \
           + @@node.get(command: 'show run snmp all')
    end

    # Delete dummy user
    config_set('snmp_user', 'user', 'no', 'dummy_user', '',
               "auth #{_auth_sym_to_str(auth_protocol)} #{dummyau}",
               "priv #{_priv_sym_to_str(priv_protocol)} #{hashed_pw}",
               'localizedkey',
               @engine_id.empty? ? '' : "engineID #{@engine_id}")
  end
  hashed_pw == current_pw
end

#priv_protocolObject



173
174
175
# File 'lib/cisco_node_utils/snmpuser.rb', line 173

def priv_protocol
  @privproto
end