Passed
Pull Request — master (#89)
by
unknown
01:45
created

gvm.protocols.gmpv8   C

Complexity

Total Complexity 54

Size/Duplication

Total Lines 364
Duplicated Lines 9.62 %

Importance

Changes 0
Metric Value
eloc 136
dl 35
loc 364
rs 6.4799
c 0
b 0
f 0
wmc 54

3 Methods

Rating   Name   Duplication   Size   Complexity  
A Gmp.get_protocol_version() 0 8 1
F Gmp.create_credential() 35 200 30
F Gmp.modify_credential() 0 104 23

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like gvm.protocols.gmpv8 often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8 -*-
2
# Copyright (C) 2018 Greenbone Networks GmbH
3
#
4
# SPDX-License-Identifier: GPL-3.0-or-later
5
#
6
# This program is free software: you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation, either version 3 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
# GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19
# pylint: disable=arguments-differ
20
21
"""
22
Module for communication with gvmd in `Greenbone Management Protocol version 8`_
23
24
**GMP Version 8 has not been released yet**
25
26
.. _Greenbone Management Protocol version 8:
27
    https://docs.greenbone.net/API/GMP/gmp-8.0.html
28
"""
29
30
from gvm.errors import InvalidArgument, RequiredArgument
31
from gvm.utils import get_version_string
32
from gvm.xml import XmlCommand
33
34
from .gmpv7 import Gmp as Gmpv7, _to_bool
35
36
CREDENTIAL_TYPES = (
37
    'cc',
38
    'snmp',
39
    'up',
40
    'usk',
41
    'smime',
42
    'pgp',
43
)
44
45
PROTOCOL_VERSION = (8,)
46
47
48
class Gmp(Gmpv7):
49
50
    @staticmethod
51
    def get_protocol_version():
52
        """Allow to determine the Greenbone Management Protocol version.
53
54
            Returns:
55
                str: Implemented version of the Greenbone Management Protocol
56
        """
57
        return get_version_string(PROTOCOL_VERSION)
58
59
    def create_credential(self, name, credential_type, *, comment=None,
0 ignored issues
show
Comprehensibility introduced by
This function exceeds the maximum number of variables (19/15).
Loading history...
60
                          allow_insecure=None, certificate=None,
61
                          key_phrase=None, private_key=None,
62
                          login=None, password=None, auth_algorithm=None,
63
                          community=None, privacy_algorithm=None,
64
                          privacy_password=None, public_key=None):
65
        """Create a new credential
66
67
        Create a new credential e.g. to be used in the method of an alert.
68
69
        Currently the following credential types are supported:
70
71
            - 'up'    - Username + Password
72
            - 'usk'   - Username + private SSH-Key
73
            - 'cc'    - Client Certificates
74
            - 'snmp'  - SNMPv1 or SNMPv2c protocol
75
            - 'smime' - S/MIME Certificate
76
            - 'pgp'   - OpenPGP Key
77
78
        Arguments:
79
            name (str): Name of the new credential
80
            credential_type (str): The credential type. One of 'cc', 'snmp',
81
                'up', 'usk', 'smime', 'pgp'
82
            comment (str, optional): Comment for the credential
83
            allow_insecure (boolean, optional): Whether to allow insecure use of
84
                the credential
85
            certificate (str, optional): Certificate for the credential.
86
                Required for cc and smime credential types.
87
            key_phrase (str, optional): Key passphrase for the private key.
88
                Used for the usk credential type.
89
            private_key (str, optional): Private key to use for login. Required
90
                for usk credential type. Also used for the cc credential type.
91
                The supported key types (dsa, rsa, ecdsa, ...) and formats (PEM,
92
                PKC#12, OpenSSL, ...) depend on your installed GnuTLS version.
93
            login (str, optional): Username for the credential. Required for
94
                up, usk and snmp credential type.
95
            password (str, optional): Password for the credential. Used for
96
                up and snmp credential types.
97
            community (str, optional): The SNMP community
98
            auth_algorithm (str, optional): The SNMP authentication algorithm.
99
                Either 'md5' or 'sha1'. Required for snmp credential type.
100
            privacy_algorithm (str, optional): The SNMP privacy algorithm,
101
                either aes or des.
102
            privacy_password (str, optional): The SNMP privacy password
103
            public_key: (str, optional): PGP public key in *armor* plain text
104
                format. Required for pgp credential type.
105
106
        Examples:
107
            Creating a Username + Password credential
108
109
            .. code-block:: python
110
111
                gmp.create_credential(
112
                    name='UP Credential',
113
                    credential_type='up',
114
                    login='foo',
115
                    password='bar',
116
                );
117
118
            Creating a Username + SSH Key credential
119
120
            .. code-block:: python
121
122
                with open('path/to/private-ssh-key') as f:
123
                    key = f.read()
124
125
                gmp.create_credential(
126
                    name='USK Credential',
127
                    credential_type='usk',
128
                    login='foo',
129
                    key_phrase='foobar',
130
                    private_key=key,
131
                )
132
133
            Creating a PGP credential
134
135
            .. note::
136
137
                A compatible public pgp key file can be exported with GnuPG via
138
                ::
139
140
                    $ gpg --armor --export [email protected] > alice.asc
141
142
            .. code-block:: python
143
144
                with open('path/to/pgp.key.asc') as f:
145
                    key = f.read()
146
147
                gmp.create_credential(
148
                    name='PGP Credential',
149
                    credential_type='pgp',
150
                    public_key=key,
151
                )
152
153
            Creating a S/MIME credential
154
155
            .. code-block:: python
156
157
                with open('path/to/smime-cert') as f:
158
                    cert = f.read()
159
160
                gmp.create_credential(
161
                    name='SMIME Credential',
162
                    credential_type='smime',
163
                    certificate=cert,
164
                )
165
166
        Returns:
167
            The response. See :py:meth:`send_command` for details.
168
        """
169
        if not name:
170
            raise RequiredArgument('create_credential requires name argument')
171
172
        if credential_type not in CREDENTIAL_TYPES:
173
            raise InvalidArgument(
174
                'create_credential requires type to be either cc, snmp, up,'
175
                'smime, pgp or usk')
176
177
        cmd = XmlCommand('create_credential')
178
        cmd.add_element('name', name)
179
180
        cmd.add_element('type', credential_type)
181
182
        if comment:
183
            cmd.add_element('comment', comment)
184
185
        if allow_insecure is not None:
186
            cmd.add_element('allow_insecure', _to_bool(allow_insecure))
187
188
189
        if credential_type == 'cc' or credential_type == 'smime':
0 ignored issues
show
Unused Code introduced by
Consider merging these comparisons with "in" to "credential_type in ('cc', 'smime')"
Loading history...
190
            if not certificate:
191
                raise RequiredArgument(
192
                    'create_credential requires certificate argument for '
193
                    'credential_type {0}'.format(credential_type))
194
195
            cmd.add_element('certificate', certificate)
196
197
        if (credential_type == 'up' or credential_type == 'usk' or \
0 ignored issues
show
Unused Code introduced by
Consider merging these comparisons with "in" to "credential_type in ('up', 'usk', 'snmp')"
Loading history...
198
                credential_type == 'snmp'):
199
            if not login:
200
                raise RequiredArgument(
201
                    'create_credential requires login argument for '
202
                    'credential_type {0}'.format(credential_type))
203
204
            cmd.add_element('login', login)
205
206
        if (credential_type == 'up' or credential_type == 'snmp') and password:
0 ignored issues
show
Unused Code introduced by
Consider merging these comparisons with "in" to "credential_type in ('up', 'snmp')"
Loading history...
207
            cmd.add_element('password', password)
208
209 View Code Duplication
        if credential_type == 'usk':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
210
            if not private_key:
211
                raise RequiredArgument(
212
                    'create_credential requires certificate argument for '
213
                    'credential_type usk')
214
215
            _xmlkey = cmd.add_element('key')
216
            _xmlkey.add_element('private', private_key)
217
218
            if key_phrase:
219
                _xmlkey.add_element('phrase', key_phrase)
220
221
        if credential_type == 'cc' and private_key:
222
            _xmlkey = cmd.add_element('key')
223
            _xmlkey.add_element('private', private_key)
224
225 View Code Duplication
        if credential_type == 'snmp':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
226
            if auth_algorithm not in ('md5', 'sha1'):
227
                raise InvalidArgument(
228
                    'create_credential requires auth_algorithm to be either '
229
                    'md5 or sha1')
230
231
            cmd.add_element('auth_algorithm', auth_algorithm)
232
233
            if community:
234
                cmd.add_element('community', community)
235
236
            if privacy_algorithm is not None or privacy_password:
237
                _xmlprivacy = cmd.add_element('privacy')
238
239
                if privacy_algorithm is not None:
240
                    if privacy_algorithm not in ('aes', 'des'):
241
                        raise InvalidArgument(
242
                            'create_credential requires algorithm to be either '
243
                            'aes or des')
244
245
                    _xmlprivacy.add_element('algorithm', privacy_algorithm)
246
247
                if privacy_password:
248
                    _xmlprivacy.add_element('password', privacy_password)
249
250
        if credential_type == 'pgp':
251
            if not public_key:
252
                raise RequiredArgument(
253
                    'Creating a pgp credential requires a public_key argument')
254
255
            _xmlkey = cmd.add_element('key')
256
            _xmlkey.add_element('public', public_key)
257
258
        return self._send_xml_command(cmd)
259
260
    def modify_credential(self, credential_id, name=None, comment=None,
0 ignored issues
show
best-practice introduced by
Too many arguments (16/15)
Loading history...
Comprehensibility introduced by
This function exceeds the maximum number of variables (20/15).
Loading history...
261
                          allow_insecure=None, certificate=None,
262
                          key_phrase=None, private_key=None, login=None,
263
                          password=None, auth_algorithm=None, community=None,
264
                          privacy_algorithm=None, privacy_password=None,
265
                          credential_type=None, public_key=None):
266
        """Modifies an existing credential.
267
268
        Arguments:
269
            credential_id (str): UUID of the credential
270
            name (str, optional): Name of the credential
271
            comment (str, optional): Comment for the credential
272
            allow_insecure (boolean, optional): Whether to allow insecure use of
273
                 the credential
274
            certificate (str, optional): Certificate for the credential
275
            key_phrase (str, optional): Key passphrase for the private key
276
            private_key (str, optional): Private key to use for login
277
            login (str, optional): Username for the credential
278
            password (str, optional): Password for the credential
279
            auth_algorithm (str, optional): The auth_algorithm,
280
                either md5 or sha1.
281
            community (str, optional): The SNMP community
282
            privacy_algorithm (str, optional): The SNMP privacy algorithm,
283
                either aes or des.
284
            privacy_password (str, optional): The SNMP privacy password
285
            credential_type (str, optional): The credential type. One of 'cc',
286
                'snmp', 'up', 'usk', 'smime', 'pgp'
287
            public_key: (str, optional): PGP public key in *armor* plain text
288
                format
289
290
        Returns:
291
            The response. See :py:meth:`send_command` for details.
292
        """
293
        if not credential_id:
294
            raise RequiredArgument('modify_credential requires '
295
                                   'a credential_id attribute')
296
297
        cmd = XmlCommand('modify_credential')
298
        cmd.set_attribute('credential_id', credential_id)
299
300
        if credential_type:
301
            if credential_type not in CREDENTIAL_TYPES:
302
                raise InvalidArgument(
303
                    'modify_credential requires type to be either cc, snmp, up '
304
                    'smime, pgp or usk'
305
                )
306
            cmd.add_element('type', credential_type)
307
308
        if comment:
309
            cmd.add_element('comment', comment)
310
311
        if name:
312
            cmd.add_element('name', name)
313
314
        if allow_insecure is not None:
315
            cmd.add_element('allow_insecure', _to_bool(allow_insecure))
316
317
        if certificate:
318
            cmd.add_element('certificate', certificate)
319
320
        if key_phrase or private_key:
321
            if not key_phrase or not private_key:
322
                raise RequiredArgument('modify_credential requires '
323
                                       'a key_phrase and private_key arguments')
324
            _xmlkey = cmd.add_element('key')
325
            _xmlkey.add_element('phrase', key_phrase)
326
            _xmlkey.add_element('private', private_key)
327
328
        if login:
329
            cmd.add_element('login', login)
330
331
        if password:
332
            cmd.add_element('password', password)
333
334
        if auth_algorithm:
335
            if auth_algorithm not in ('md5', 'sha1'):
336
                raise InvalidArgument('modify_credential requires '
337
                                      'auth_algorithm to be either '
338
                                      'md5 or sha1')
339
            cmd.add_element('auth_algorithm', auth_algorithm)
340
341
        if community:
342
            cmd.add_element('community', community)
343
344
        if privacy_algorithm is not None or privacy_password is not None:
345
            _xmlprivacy = cmd.add_element('privacy')
346
347
            if privacy_algorithm is not None:
348
                if privacy_algorithm not in ('aes', 'des'):
349
                    raise InvalidArgument(
350
                        'modify_credential requires privacy_algorithm to be '
351
                        'either aes or des'
352
                    )
353
354
                _xmlprivacy.add_element('algorithm', privacy_algorithm)
355
356
            if privacy_password is not None:
357
                _xmlprivacy.add_element('password', privacy_password)
358
359
        if public_key:
360
            _xmlkey = cmd.add_element('key')
361
            _xmlkey.add_element('public', public_key)
362
363
        return self._send_xml_command(cmd)
364