Skip to content
Merged
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
cfe0aa7
Fix the visibility of action secret parameters on rule
jeansfelix Sep 12, 2019
0f1bae2
Fix PEP8
jeansfelix Sep 12, 2019
c604c15
Merge branch 'master' into fix/mask-secrets-rule-parameters
jeansfelix Sep 12, 2019
4f7f7a1
Add tests when secrets masking works correctly when ?include_attribut…
Nicodemos305 Oct 9, 2019
36980e5
Change name method test_get_one_parameters_mask_with_include_paramete…
Nicodemos305 Oct 9, 2019
6b9eb4e
add assertequal for length of json
Nicodemos305 Oct 9, 2019
42eb393
Add test model test_rule_with_secret_parameter_masked
Nicodemos305 Oct 9, 2019
76cd651
Fix syntax error
Nicodemos305 Oct 10, 2019
5defcda
Fix api path
Nicodemos305 Oct 10, 2019
421321d
Add default value p4 parameter
Nicodemos305 Oct 10, 2019
0cc4cb5
Include import constant
Nicodemos305 Oct 10, 2019
c07522a
Fix whitespace
Nicodemos305 Oct 10, 2019
8b01949
Fix delete before finish test method
Nicodemos305 Oct 10, 2019
9f3feaf
Fix parameters
Nicodemos305 Oct 10, 2019
7ff661e
Fix parameters
Nicodemos305 Oct 10, 2019
4182f4b
Remove blank lines
Nicodemos305 Oct 10, 2019
46dd3fa
Simple string in secret true parameter
Nicodemos305 Oct 10, 2019
7ad78a9
Add import RuleTypeDB
Nicodemos305 Oct 11, 2019
4c0fd03
Fix test_rule_with_secret_parameter_masked
Nicodemos305 Oct 11, 2019
3271499
Fix test_rule_with_secret_parameter_masked
Nicodemos305 Oct 11, 2019
4ffaa6f
Remove test test_rule_with_secret_parameter_masked
Nicodemos305 Oct 11, 2019
4d7e552
Remove parameters p4
Nicodemos305 Oct 11, 2019
ee220c1
Fix syntax error
Nicodemos305 Oct 11, 2019
b73e1c3
Remove unnecessary constant
Nicodemos305 Oct 11, 2019
a202c4b
Remove All tests test_get_all_parameters_mask_with_include_parameters…
Nicodemos305 Oct 11, 2019
1ca2854
Add tests with include_attribute and exclude_attributes
Nicodemos305 Oct 11, 2019
a644014
Model tests done, WIP API Tests
Nicodemos305 Oct 16, 2019
8faa9ab
Fix get api rule include attribute
Nicodemos305 Oct 17, 2019
a1b97c6
Include test key action in map rule
Nicodemos305 Oct 17, 2019
07d4eb7
Clean Lint errors
Nicodemos305 Oct 17, 2019
b3a7531
Fix lin rule.py
Nicodemos305 Oct 17, 2019
8277c78
Fix test rule
Nicodemos305 Oct 17, 2019
61b8b58
Fix Db rule
Nicodemos305 Oct 17, 2019
f1c4de4
Fix method ref_query_args
Nicodemos305 Oct 17, 2019
8b85474
Fix Lint
Nicodemos305 Oct 17, 2019
cb3b35c
Merge branch 'master' into fix/mask-secrets-rule-parameters
blag Oct 18, 2019
4614d44
Add changelog Added mask of rule action secret parameters #4788
Nicodemos305 Oct 18, 2019
8e80197
Merge branch 'fix/mask-secrets-rule-parameters' of github.com:pepepro…
Nicodemos305 Oct 18, 2019
dcfe02f
Fix changelog entry.
Kami Oct 29, 2019
bf421a3
Don't break the DB abstraction and use persistance class to query for
Kami Oct 29, 2019
70f960b
get one and get all rules api endpoint show also support
Kami Oct 29, 2019
3400a76
Add some test cases which verify secrets masking works correctly for
Kami Oct 29, 2019
0343096
Fix lint, add missing change.
Kami Oct 29, 2019
3dc9ca1
Merge branch 'master' into fix/mask-secrets-rule-parameters
Kami Oct 29, 2019
bfafd43
Remove unused method, fix docstring.
Kami Oct 29, 2019
ec6b7fd
Add additional clarification.
Kami Oct 29, 2019
1022c1e
Merge branch 'master' into fix/mask-secrets-rule-parameters
Kami Oct 30, 2019
06628a7
Update changelog.
Kami Oct 30, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ Fixed
doesn't depend on internal pip API and so it works with latest pip version. (bug fix) #4750
* Fix dependency conflicts in pack CI runs: downgrade requests dependency back to 0.21.0, update
internal dependencies and test expectations (amqp, pyyaml, prance, six) (bugfix) #4774
* Fix mask of rule action secret parameters:

When we had an action on a rule with secret type parameters, the parameters were visible. This
behavior has been resolved in #4788
Contributed by @Nicodemos305 and @jeansfelix #4788

3.1.0 - June 27, 2019
---------------------
Expand Down
3 changes: 2 additions & 1 deletion st2api/st2api/controllers/v1/rule_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,9 @@ def get_all(self, exclude_attributes=None, include_attributes=None, sort=None, o
return rules

def get_one(self, ref_or_id, requester_user):
from_model_kwargs = {'mask_secrets': True}
rule = self._get_one(ref_or_id, permission_type=PermissionType.RULE_VIEW,
requester_user=requester_user)
requester_user=requester_user, from_model_kwargs=from_model_kwargs)
result = self._append_view_properties([rule.json])[0]
rule.json = result
return rule
Expand Down
18 changes: 13 additions & 5 deletions st2api/st2api/controllers/v1/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from st2common import log as logging
from st2common.exceptions.apivalidation import ValueValidationException
from st2common.exceptions.triggers import TriggerDoesNotExistException
from st2api.controllers.base import BaseRestControllerMixin
from st2api.controllers.resource import BaseResourceIsolationControllerMixin
from st2api.controllers.resource import ContentPackResourceController
from st2api.controllers.controller_transforms import transform_to_bool
Expand All @@ -39,7 +40,8 @@
LOG = logging.getLogger(__name__)


class RuleController(BaseResourceIsolationControllerMixin, ContentPackResourceController):
class RuleController(BaseRestControllerMixin, BaseResourceIsolationControllerMixin,
ContentPackResourceController):
"""
Implements the RESTful web endpoint that handles
the lifecycle of Rules in the system.
Expand Down Expand Up @@ -68,8 +70,11 @@ class RuleController(BaseResourceIsolationControllerMixin, ContentPackResourceCo
mandatory_include_fields_retrieve = ['pack', 'name', 'trigger']

def get_all(self, exclude_attributes=None, include_attributes=None, sort=None, offset=0,
limit=None, requester_user=None, **raw_filters):
from_model_kwargs = {'ignore_missing_trigger': True}
limit=None, show_secrets=False, requester_user=None, **raw_filters):
from_model_kwargs = {
'ignore_missing_trigger': True,
'mask_secrets': self._get_mask_secrets(requester_user, show_secrets=show_secrets)
}
return super(RuleController, self)._get_all(exclude_fields=exclude_attributes,
include_fields=include_attributes,
from_model_kwargs=from_model_kwargs,
Expand All @@ -79,8 +84,11 @@ def get_all(self, exclude_attributes=None, include_attributes=None, sort=None, o
raw_filters=raw_filters,
requester_user=requester_user)

def get_one(self, ref_or_id, requester_user):
from_model_kwargs = {'ignore_missing_trigger': True}
def get_one(self, ref_or_id, requester_user, show_secrets=False):
from_model_kwargs = {
'ignore_missing_trigger': True,
'mask_secrets': self._get_mask_secrets(requester_user, show_secrets=show_secrets)
}
return super(RuleController, self)._get_one(ref_or_id, from_model_kwargs=from_model_kwargs,
requester_user=requester_user,
permission_type=PermissionType.RULE_VIEW)
Expand Down
53 changes: 53 additions & 0 deletions st2api/tests/unit/controllers/v1/test_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

from st2common.constants.rules import RULE_TYPE_STANDARD, RULE_TYPE_BACKSTOP
from st2common.constants.pack import DEFAULT_PACK_NAME
from st2common.constants.secrets import MASKED_ATTRIBUTE_VALUE
from st2common.persistence.trigger import Trigger
from st2common.models.system.common import ResourceReference
from st2common.transport.publishers import PoolPublisher
Expand Down Expand Up @@ -185,6 +186,58 @@ def test_get_all_enabled(self):
self.__do_delete(self.__get_rule_id(post_resp_rule_1))
self.__do_delete(self.__get_rule_id(post_resp_rule_3))

def test_get_all_action_parameters_secrets_masking(self):
post_resp_rule_1 = self.__do_post(RulesControllerTestCase.RULE_1)

# Verify parameter is masked by default
resp = self.app.get('/v1/rules')
self.assertEqual('action' in resp.json[0], True)
self.assertEqual(resp.json[0]['action']['parameters']['action_secret'],
MASKED_ATTRIBUTE_VALUE)

# Verify ?show_secrets=true works
resp = self.app.get('/v1/rules?include_attributes=action&show_secrets=true')
self.assertEqual('action' in resp.json[0], True)
self.assertEqual(resp.json[0]['action']['parameters']['action_secret'], 'secret')

self.__do_delete(self.__get_rule_id(post_resp_rule_1))

def test_get_all_parameters_mask_with_exclude_parameters(self):
post_resp_rule_1 = self.__do_post(RulesControllerTestCase.RULE_1)
resp = self.app.get('/v1/rules?exclude_attributes=action')
self.assertEqual('action' in resp.json[0], False)
self.__do_delete(self.__get_rule_id(post_resp_rule_1))

def test_get_all_parameters_mask_with_include_parameters(self):
post_resp_rule_1 = self.__do_post(RulesControllerTestCase.RULE_1)

# Verify parameter is masked by default
resp = self.app.get('/v1/rules?include_attributes=action')
self.assertEqual('action' in resp.json[0], True)
self.assertEqual(resp.json[0]['action']['parameters']['action_secret'],
MASKED_ATTRIBUTE_VALUE)

# Verify ?show_secrets=true works
resp = self.app.get('/v1/rules?include_attributes=action&show_secrets=true')
self.assertEqual('action' in resp.json[0], True)
self.assertEqual(resp.json[0]['action']['parameters']['action_secret'], 'secret')

self.__do_delete(self.__get_rule_id(post_resp_rule_1))

def test_get_one_action_parameters_secrets_masking(self):
post_resp_rule_1 = self.__do_post(RulesControllerTestCase.RULE_1)

# Verify parameter is masked by default
resp = self.app.get('/v1/rules/%s' % (post_resp_rule_1.json['id']))
self.assertEqual(resp.json['action']['parameters']['action_secret'],
MASKED_ATTRIBUTE_VALUE)

# Verify ?show_secrets=true works
resp = self.app.get('/v1/rules/%s?show_secrets=true' % (post_resp_rule_1.json['id']))
self.assertEqual(resp.json['action']['parameters']['action_secret'], 'secret')

self.__do_delete(self.__get_rule_id(post_resp_rule_1))

def test_get_one_by_id(self):
post_resp = self.__do_post(RulesControllerTestCase.RULE_1)
rule_id = self.__get_rule_id(post_resp)
Expand Down
53 changes: 53 additions & 0 deletions st2common/st2common/models/db/rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@
# limitations under the License.

from __future__ import absolute_import
import copy
import mongoengine as me

from st2common.persistence.action import Action
from st2common.models.db import MongoDBAccess
from st2common.models.db import stormbase
from st2common.constants.types import ResourceType
from st2common.util.secrets import get_secret_parameters
from st2common.util.secrets import mask_secret_parameters


class RuleTypeDB(stormbase.StormBaseDB):
Expand Down Expand Up @@ -101,6 +105,55 @@ class RuleDB(stormbase.StormFoundationDB, stormbase.TagsMixin,
stormbase.UIDFieldMixin.get_indexes())
}

def mask_secrets(self, value):
"""
Process the model dictionary and mask secret values.

NOTE: This method results in one addition "get one" query where we retrieve corresponding
action model so we can correctly mask secret parameters.

:type value: ``dict``
:param value: Document dictionary.

:rtype: ``dict``
"""
result = copy.deepcopy(value)

action_ref = result.get('action', {}).get('ref', None)

if not action_ref:
return result

action_db = self._get_referenced_action_model(action_ref=action_ref)

if not action_db:
return result

secret_parameters = get_secret_parameters(parameters=action_db.parameters)
result['action']['parameters'] = mask_secret_parameters(
parameters=result['action']['parameters'],
secret_parameters=secret_parameters)

return result

def _get_referenced_action_model(self, action_ref):
"""
Return Action object for the action referenced in a rule.

:param action_ref: Action reference.
:type action_ref: ``str``

:rtype: ``ActionDB``
"""
# NOTE: We need to retrieve pack and name since that's needed for the PK
action_dbs = Action.query(only_fields=['pack', 'ref', 'name', 'parameters'],
ref=action_ref, limit=1)

if action_dbs:
return action_dbs[0]

return None

def __init__(self, *args, **values):
super(RuleDB, self).__init__(*args, **values)
self.ref = self.get_reference().ref
Expand Down
8 changes: 8 additions & 0 deletions st2common/st2common/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2649,6 +2649,10 @@ paths:
in: query
description: Enabled filter
type: string
- name: show_secrets
in: query
description: Show secrets in plain text
type: boolean
x-parameters:
- name: user
in: context
Expand Down Expand Up @@ -2710,6 +2714,10 @@ paths:
description: Entity reference or id
type: string
required: true
- name: show_secrets
in: query
description: Show secrets in plain text
type: boolean
x-parameters:
- name: user
in: context
Expand Down
8 changes: 8 additions & 0 deletions st2common/st2common/openapi.yaml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -2645,6 +2645,10 @@ paths:
in: query
description: Enabled filter
type: string
- name: show_secrets
in: query
description: Show secrets in plain text
type: boolean
x-parameters:
- name: user
in: context
Expand Down Expand Up @@ -2706,6 +2710,10 @@ paths:
description: Entity reference or id
type: string
required: true
- name: show_secrets
in: query
description: Show secrets in plain text
type: boolean
x-parameters:
- name: user
in: context
Expand Down
10 changes: 7 additions & 3 deletions st2common/tests/unit/test_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import mongoengine.connection
from oslo_config import cfg
from pymongo.errors import ConnectionFailure

from st2common.constants.triggers import TRIGGER_INSTANCE_PROCESSED
from st2common.models.system.common import ResourceReference
from st2common.transport.publishers import PoolPublisher
Expand Down Expand Up @@ -521,6 +520,10 @@ def _delete(model_objects):
"p3": {
"type": "boolean",
"default": False
},
"p4": {
"type": "string",
"secret": True
}
},
"additionalProperties": False
Expand Down Expand Up @@ -661,12 +664,13 @@ def _create_save_action(runnertype, metadata=False):
runner_type={'name': runnertype.name})

if not metadata:
created.parameters = {'p1': None, 'p2': None, 'p3': None}
created.parameters = {'p1': None, 'p2': None, 'p3': None, 'p4': None}
else:
created.parameters = {
'p1': {'type': 'string', 'required': True},
'p2': {'type': 'number', 'default': 2868},
'p3': {'type': 'boolean', 'default': False}
'p3': {'type': 'boolean', 'default': False},
'p4': {'type': 'string', 'secret': True}
}
return Action.add_or_update(created)

Expand Down
3 changes: 3 additions & 0 deletions st2tests/st2tests/fixtures/generic/actions/action1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ parameters:
async_test:
default: false
type: boolean
action_secret:
type: string
secret: true
runnerdummy:
default: actiondummy
immutable: true
Expand Down
1 change: 1 addition & 0 deletions st2tests/st2tests/fixtures/generic/rules/rule1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ action:
parameters:
ip1: '{{trigger.t1_p}}'
ip2: '{{trigger}}'
action_secret: 'secret'
ref: wolfpack.action-1
criteria:
trigger.t1_p:
Expand Down