| Total Complexity | 54 |
| Total Lines | 364 |
| Duplicated Lines | 9.62 % |
| Changes | 0 | ||
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:
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, |
||
|
|
|||
| 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': |
||
| 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 \ |
||
| 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: |
||
| 207 | cmd.add_element('password', password) |
||
| 208 | |||
| 209 | View Code Duplication | if credential_type == 'usk': |
|
| 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': |
|
| 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, |
||
| 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 |