Skip to content

Commit d997130

Browse files
skorandac00kiemon5ter
authored andcommitted
Pull YAML configuration values from environment
Add logic so that a YAML tag of the form !ENV indicates that a value of the form ${SOME_ENVIRONMENT_VARIABLE} should be replaced with the value of the process environment variable of the same name.
1 parent 1c02692 commit d997130

File tree

4 files changed

+53
-1
lines changed

4 files changed

+53
-1
lines changed

doc/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,23 @@ apt-get install libffi-dev libssl-dev xmlsec1
2929
Alternatively the application can be installed directly from PyPI (`pip install satosa`), or the [Docker image](https://hub.docker.com/r/satosa/) can be used.
3030

3131
# Configuration
32+
SATOSA is configured using YAML.
33+
3234
All default configuration files, as well as an example WSGI application for the proxy, can be found
3335
in the [example directory](../example).
3436

37+
A configuration value that includes the tag !ENV will have a value of the form `${SOME_ENVIRONMENT_VARIABLE}`
38+
replaced with the value from the process environment variable of the same name. For example if the file
39+
`ldap_attribute_store.yaml' includes
40+
41+
```
42+
bind_password: !ENV ${LDAP_BIND_PASSWORD}
43+
```
44+
45+
and the SATOSA process environment includes the environment variable `LDAP_BIND_PASSWORD` with
46+
value `my_password` then the configuration for `bind_password` will be `my_password`.
47+
48+
3549
## <a name="proxy_conf" style="color:#000000">SATOSA proxy configuration</a>: `proxy_conf.yaml.example`
3650
| Parameter name | Data type | Example value | Description |
3751
| -------------- | --------- | ------------- | ----------- |

example/plugins/microservices/ldap_attribute_store.yaml.example

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ config:
88
"":
99
ldap_url: ldaps://ldap.example.org
1010
bind_dn: cn=admin,dc=example,dc=org
11-
bind_password: xxxxxxxx
11+
# Obtain bind password from environment variable LDAP_BIND_PASSWORD.
12+
bind_password: !ENV ${LDAP_BIND_PASSWORD}
1213
search_base: ou=People,dc=example,dc=org
1314
read_only: true
1415
auto_bind: true

src/satosa/satosa_config.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""
44
import logging
55
import os
6+
import re
67

78
import yaml
89

@@ -143,6 +144,33 @@ def _load_yaml(self, config_file):
143144
:param config_file: config to load. Can be file path or yaml string
144145
:return: Loaded config
145146
"""
147+
# Tag to indicate environment variable: !ENV
148+
tag = '!ENV'
149+
150+
# Pattern for environment variable: ${word}
151+
pattern = re.compile('.*?\${(\w+)}.*?')
152+
153+
yaml.SafeLoader.add_implicit_resolver(tag, pattern, None)
154+
155+
def constructor_env_variables(loader, node):
156+
"""
157+
Extracts the environment variable from the node's value.
158+
:param yaml.Loader loader: the yaml loader
159+
:param node: the current node in the yaml
160+
:return: value of the environment variable
161+
"""
162+
value = loader.construct_scalar(node)
163+
match = pattern.findall(value)
164+
if match:
165+
new_value = value
166+
for m in match:
167+
new_value = new_value.replace('${' + m + '}',
168+
os.environ.get(m, m))
169+
return new_value
170+
return value
171+
172+
yaml.SafeLoader.add_constructor(tag, constructor_env_variables)
173+
146174
try:
147175
with open(os.path.abspath(config_file)) as f:
148176
return yaml.safe_load(f.read())

tests/satosa/test_satosa_config.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import json
2+
import os
23
from unittest.mock import mock_open, patch
34

45
import pytest
@@ -7,6 +8,7 @@
78
from satosa.exception import SATOSAConfigurationError
89
from satosa.satosa_config import SATOSAConfig
910

11+
TEST_RESOURCE_BASE_PATH = os.path.join(os.path.dirname(__file__), "../test_resources")
1012

1113
class TestSATOSAConfig:
1214
@pytest.fixture
@@ -73,3 +75,10 @@ def test_can_read_endpoint_configs_from_file(self, satosa_config_dict, modules_k
7375

7476
with pytest.raises(SATOSAConfigurationError):
7577
SATOSAConfig(satosa_config_dict)
78+
79+
def test_can_substitute_from_environment_variable(self, monkeypatch):
80+
monkeypatch.setenv("SATOSA_COOKIE_STATE_NAME", "oatmeal_raisin")
81+
config = SATOSAConfig(os.path.join(TEST_RESOURCE_BASE_PATH,
82+
"proxy_conf_environment_test.yaml"))
83+
84+
assert config["COOKIE_STATE_NAME"] == 'oatmeal_raisin'

0 commit comments

Comments
 (0)