Skip to content

Commit

Permalink
Merge pull request #25 from splunk-soar-connectors/mposluszny/PAPP-32933
Browse files Browse the repository at this point in the history
PAPP-32933 Mswinrm: Feature - support for kerberos and certificate auth methods
  • Loading branch information
mposluszny-splunk authored Feb 28, 2024
2 parents caa2ef5 + 95bd9d9 commit 97735c7
Show file tree
Hide file tree
Showing 22 changed files with 207 additions and 18 deletions.
3 changes: 2 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
repos:
- repo: https://github.com/phantomcyber/dev-cicd-tools
rev: v1.16
rev: v1.17
hooks:
- id: org-hook
- id: package-app-dependencies
args: ["-d", "./Dockerfile.wheels"]
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
Expand Down
2 changes: 2 additions & 0 deletions Dockerfile.wheels
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
FROM quay.io/pypa/manylinux2014_x86_64
RUN yum install krb5-devel krb5-workstation -y
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,4 @@
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
limitations under the License.
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,33 @@ or some other command which you want to start but don't care for the output, the
**async** parameter. After the command starts, it will return a **command_id** and **shell_id** ,
which you can optionally use to retrieve the output of that command at a later time.
### Certificate Authentication
To authenticate using SSL certificates, select `certificate` authentication in asset configuration method and pass following configuration parameters.
* cert_pem_path - A path to signed certificate file that is trusted by the Windows instance, in PEM format
* cert_key_pem_path - A filepath to key used to generate cert_pem file
* ca_trust_path - The certificate of the certificate authority that signed cert_file. It's needed only when you set up your own certificate authority.
It is recommended that these files be placed under the <PHANTOM_HOME>/etc/ssl/ directory. These files must be readable by the phantom-worker user.
### Kerberos Authentication
To authenticate using Kerberos, select `kerberos` authentication in asset configuration and provide hostname and username used for authorization.
You'll also need to setup your instance to support Kerberos:
- Kerberos packages have to be installed:
- for Debian/Ubuntu/etc: `sudo apt-get install krb5-user`
- for RHEL/CentOS/etc: `sudo yum install krb5-workstation krb5-libs krb5-auth-dialog`
- `/etc/krb5.conf` needs to be properly configured for your realm and kdc
- If there is no DNS configuration, `hosts` file will need to have mappings for server with mssccm under same domain as on Windows server
- `kinit` must be run for principal that will be used to connect to msccm
- It should be noted that Kerberos tickets will expire, so it is recommended to use a script to
run `kinit` periodically to refresh the ticket for the user, alternatively `keytab` file can be created on server and used on client for connectivity.
### Configuration Variables
The below configuration variables are required for this Connector to operate. These variables are specified when configuring a Windows Remote Management asset in SOAR.
Expand All @@ -144,6 +171,9 @@ VARIABLE | REQUIRED | TYPE | DESCRIPTION
**username** | required | string | Username
**password** | required | password | Password
**transport** | required | string | Type of transport to use
**cert_pem_path** | optional | string | Path to SSL certificate PEM file
**cert_key_pem_path** | optional | string | Path to SSL key file
**ca_trust_path** | optional | string | Path to trusted CRT file
### Supported Actions
[test connectivity](#action-test-connectivity) - Validate the asset configuration for connectivity using supplied configuration
Expand Down
27 changes: 27 additions & 0 deletions manual_readme_content.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,30 @@ default, the app will wait for these actions to finish. In the case of starting
or some other command which you want to start but don't care for the output, then you can check the
**async** parameter. After the command starts, it will return a **command_id** and **shell_id** ,
which you can optionally use to retrieve the output of that command at a later time.
### Certificate Authentication
To authenticate using SSL certificates, select `certificate` authentication in asset configuration method and pass following configuration parameters.
* cert_pem_path - A path to signed certificate file that is trusted by the Windows instance, in PEM format
* cert_key_pem_path - A filepath to key used to generate cert_pem file
* ca_trust_path - The certificate of the certificate authority that signed cert_file. It's needed only when you set up your own certificate authority.
It is recommended that these files be placed under the <PHANTOM_HOME>/etc/ssl/ directory. These files must be readable by the phantom-worker user.
### Kerberos Authentication
To authenticate using Kerberos, select `kerberos` authentication in asset configuration and provide hostname and username used for authorization.
You'll also need to setup your instance to support Kerberos:
- Kerberos packages have to be installed:
- for Debian/Ubuntu/etc: `sudo apt-get install krb5-user`
- for RHEL/CentOS/etc: `sudo yum install krb5-workstation krb5-libs krb5-auth-dialog`
- `/etc/krb5.conf` needs to be properly configured for your realm and kdc
- If there is no DNS configuration, `hosts` file will need to have mappings for server with mssccm under same domain as on Windows server
- `kinit` must be run for principal that will be used to connect to msccm
- It should be noted that Kerberos tickets will expire, so it is recommended to use a script to
run `kinit` periodically to refresh the ticket for the user, alternatively `keytab` file can be created on server and used on client for connectivity.
3 changes: 3 additions & 0 deletions release_notes/unreleased.md
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
**Unreleased**

* [PAPP-32933] Kerberos and Certificate authentication support.
* User can now select Certificate and Kerberos as transport methods
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
beautifulsoup4==4.9.1
pykerberos==1.2.4
pywinrm==0.4.3
# Pinned to the current platform version
requests==2.31.0
Expand Down
Binary file not shown.
Binary file added wheels/py3/soupsieve-2.3.2.post1-py3-none-any.whl
Binary file not shown.
Binary file added wheels/py3/urllib3-2.2.1-py3-none-any.whl
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
98 changes: 95 additions & 3 deletions winrm.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,30 @@
"required": true,
"value_list": [
"basic",
"ntlm"
"ntlm",
"certificate",
"kerberos"
],
"default": "basic",
"order": 7
},
"cert_pem_path": {
"description": "Path to SSL certificate PEM file",
"data_type": "string",
"required": false,
"order": 8
},
"cert_key_pem_path": {
"description": "Path to SSL key file",
"data_type": "string",
"required": false,
"order": 9
},
"ca_trust_path": {
"description": "Path to trusted CRT file",
"data_type": "string",
"required": false,
"order": 10
}
},
"actions": [
Expand Down Expand Up @@ -3321,7 +3341,7 @@
},
{
"module": "cryptography",
"input_file": "wheels/py39/cryptography-42.0.2-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"
"input_file": "wheels/py39/cryptography-42.0.4-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"
},
{
"module": "idna",
Expand All @@ -3331,6 +3351,10 @@
"module": "pycparser",
"input_file": "wheels/shared/pycparser-2.21-py2.py3-none-any.whl"
},
{
"module": "pykerberos",
"input_file": "wheels/py39/pykerberos-1.2.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
},
{
"module": "pyspnego",
"input_file": "wheels/py3/pyspnego-0.10.2-py3-none-any.whl"
Expand All @@ -3355,6 +3379,74 @@
"module": "soupsieve",
"input_file": "wheels/py3/soupsieve-2.5-py3-none-any.whl"
},
{
"module": "urllib3",
"input_file": "wheels/py3/urllib3-2.2.1-py3-none-any.whl"
},
{
"module": "xmltodict",
"input_file": "wheels/shared/xmltodict-0.13.0-py2.py3-none-any.whl"
}
]
},
"pip_dependencies": {
"wheel": [
{
"module": "beautifulsoup4",
"input_file": "wheels/py3/beautifulsoup4-4.9.1-py3-none-any.whl"
},
{
"module": "certifi",
"input_file": "wheels/py3/certifi-2024.2.2-py3-none-any.whl"
},
{
"module": "cffi",
"input_file": "wheels/py36/cffi-1.15.1-cp36-cp36m-manylinux1_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
},
{
"module": "charset_normalizer",
"input_file": "wheels/py3/charset_normalizer-2.0.12-py3-none-any.whl"
},
{
"module": "cryptography",
"input_file": "wheels/py36/cryptography-40.0.2-cp36-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl"
},
{
"module": "idna",
"input_file": "wheels/py3/idna-3.6-py3-none-any.whl"
},
{
"module": "ntlm_auth",
"input_file": "wheels/shared/ntlm_auth-1.5.0-py2.py3-none-any.whl"
},
{
"module": "pycparser",
"input_file": "wheels/shared/pycparser-2.21-py2.py3-none-any.whl"
},
{
"module": "pykerberos",
"input_file": "wheels/py36/pykerberos-1.2.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
},
{
"module": "pywinrm",
"input_file": "wheels/shared/pywinrm-0.4.3-py2.py3-none-any.whl"
},
{
"module": "requests",
"input_file": "wheels/shared/requests-2.27.1-py2.py3-none-any.whl"
},
{
"module": "requests_ntlm",
"input_file": "wheels/shared/requests_ntlm-1.1.0-py2.py3-none-any.whl"
},
{
"module": "six",
"input_file": "wheels/shared/six-1.16.0-py2.py3-none-any.whl"
},
{
"module": "soupsieve",
"input_file": "wheels/py3/soupsieve-2.3.2.post1-py3-none-any.whl"
},
{
"module": "urllib3",
"input_file": "wheels/shared/urllib3-1.26.18-py2.py3-none-any.whl"
Expand All @@ -3365,4 +3457,4 @@
}
]
}
}
}
46 changes: 33 additions & 13 deletions winrm_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from bs4 import UnicodeDammit
from phantom.action_result import ActionResult
from phantom.base_connector import BaseConnector
from phantom_common.install_info import is_fips_enabled

# Local imports
import parse_callbacks as pc
Expand Down Expand Up @@ -187,6 +188,11 @@ def _sanitize_string(self, string):
# break any double quotes which are found, then we break any $, which is used to declare variables
return string.replace('`', '``').replace('"', '`"').replace('$', '`$').replace('&', '`&').replace(')', '`)').replace('(', '`(')

def _get_fips_enabled(self):
fips_enabled = is_fips_enabled()
self.debug_print(f'FIPS is enabled: {fips_enabled}')
return fips_enabled

def _create_ps_script(self, action_result, args, whitelist_args=set(), cmd_prefix="", cmd_suffix=""):
# Here, you can pass it something like {"val1": "value"} which will generate a string for "-val1 value"
# "For your convenience" you can also pass it a list of strings and dicts, something like [val1, {"val2": "asdf"}, foo],
Expand Down Expand Up @@ -224,19 +230,19 @@ def _create_ps_script(self, action_result, args, whitelist_args=set(), cmd_prefi
def _init_session(self, action_result, param=None):
config = self.get_config()

default_protocol = config.get('default_protocol', 'http')
default_protocol = config.get(consts.WINRM_CONFIG_PROTOCOL, 'http')
ret_val, default_port = self._validate_integer(
action_result,
config.get('default_port', 5985 if default_protocol == 'http' else 5986),
config.get(consts.WINRM_CONFIG_PORT, 5985 if default_protocol == 'http' else 5986),
"Default port",
True)
if phantom.is_fail(ret_val):
return action_result.get_status()

endpoint = self._handle_py_ver_compat_for_input_str(config.get(consts.WINRM_CONFIG_ENDPOINT))
if param:
endpoint = self._handle_py_ver_compat_for_input_str(param.get('ip_hostname', config.get('endpoint')))
else:
endpoint = self._handle_py_ver_compat_for_input_str(config.get('endpoint'))
endpoint = self._handle_py_ver_compat_for_input_str(param.get('ip_hostname', endpoint))

if endpoint is None:
return action_result.set_status(
phantom.APP_ERROR, "No Endpoint Configured"
Expand All @@ -245,12 +251,16 @@ def _init_session(self, action_result, param=None):
endpoint = '{0}://{1}'.format(default_protocol, endpoint)
if re.search(r':\d+$', endpoint, re.UNICODE | re.IGNORECASE) is None:
endpoint = '{0}:{1}'.format(endpoint, default_port)
username = config['username']
password = config['password']
transport = config.get('transport')
domain = self._handle_py_ver_compat_for_input_str(config.get('domain'))
username = config[consts.WINRM_CONFIG_USERNAME]
password = config[consts.WINRM_CONFIG_PASSWORD]
transport = config.get(consts.WINRM_CONFIG_TRANSPORT)
domain = self._handle_py_ver_compat_for_input_str(config.get(consts.WINRM_CONFIG_DOMAIN))

verify_bool = config.get(phantom.APP_JSON_VERIFY, False)
cert_pem_path = None
cert_key_pem_path = None
cert_ca_trust_path = config.get(consts.WINRM_CONFIG_CA_TRUST, "legacy_requests")

if verify_bool:
verify = 'validate'
else:
Expand All @@ -262,12 +272,19 @@ def _init_session(self, action_result, param=None):
"Warning: Domain is set but transport type is set to 'basic'"
)
elif transport == 'ntlm':
if self._get_fips_enabled():
return action_result.set_status(
phantom.APP_ERROR, "This transport type is not supported when FIPS is enabled"
)
if domain:
username = r'{}\{}'.format(domain, username)
elif transport == 'kerberos':
return action_result.set_status(
phantom.APP_ERROR, "This transport type is not yet implemented"
)
if domain:
username = '{}@{}'.format(username, domain)
elif transport == 'certificate':
username = r'{}\{}'.format(domain, username)
cert_pem_path = config.get(consts.WINRM_CONFIG_CERT_PEM)
cert_key_pem_path = config.get(consts.WINRM_CONFIG_CERT_KEY_PEM)
elif transport == 'credssp':
return action_result.set_status(
phantom.APP_ERROR, "This transport type is not yet implemented"
Expand All @@ -281,7 +298,10 @@ def _init_session(self, action_result, param=None):
endpoint,
auth=(username, password),
server_cert_validation=verify,
transport=transport
transport=transport,
cert_pem=cert_pem_path,
cert_key_pem=cert_key_pem_path,
ca_trust_path=cert_ca_trust_path
)
self._protocol = self._session.protocol

Expand Down
13 changes: 13 additions & 0 deletions winrm_consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,16 @@
LOCATION_VALUE_LIST = ["local", "domain", "effective"]
DENY_ALLOW_VALUE_LIST = ["deny", "allow"]
VALUE_LIST_VALIDATION_MESSAGE = "Please provide valid input from {} in '{}' action parameter"

# Config keys

WINRM_CONFIG_ENDPOINT = "endpoint"
WINRM_CONFIG_PROTOCOL = "default_protocol"
WINRM_CONFIG_PORT = "default_port"
WINRM_CONFIG_USERNAME = "username"
WINRM_CONFIG_PASSWORD = "password"
WINRM_CONFIG_TRANSPORT = "transport"
WINRM_CONFIG_DOMAIN = "domain"
WINRM_CONFIG_CERT_PEM = "cert_pem_path"
WINRM_CONFIG_CERT_KEY_PEM = "cert_key_pem_path"
WINRM_CONFIG_CA_TRUST = "ca_trust_path"

0 comments on commit 97735c7

Please sign in to comment.