Skip to content

Commit 022f989

Browse files
skorandac00kiemon5ter
authored andcommitted
Pull YAML configuration values from file pointed to by environment
Add logic so that a YAML tag of the form !ENVFILE indicates that a value of the form $(SOME_ENVIRONMENT_VARIABLE_FILE) should be replaced with the value obtained by reading the process environment variable of the same name to get a file path and then reading the file contents.
1 parent 9991b1a commit 022f989

File tree

5 files changed

+61
-5
lines changed

5 files changed

+61
-5
lines changed

example/plugins/microservices/ldap_attribute_store.yaml.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ config:
1010
bind_dn: cn=admin,dc=example,dc=org
1111
# Obtain bind password from environment variable LDAP_BIND_PASSWORD.
1212
bind_password: !ENV ${LDAP_BIND_PASSWORD}
13+
# Obtain bind password from file pointed to by
14+
# environment variable LDAP_BIND_PASSWORD_FILE.
15+
# bind_password: !ENVFILE $(LDAP_BIND_PASSWORD)
1316
search_base: ou=People,dc=example,dc=org
1417
read_only: true
1518
auto_bind: true

src/satosa/satosa_config.py

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""
44
import logging
55
import os
6+
import os.path
67
import re
78

89
import yaml
@@ -145,12 +146,12 @@ def _load_yaml(self, config_file):
145146
:return: Loaded config
146147
"""
147148
# Tag to indicate environment variable: !ENV
148-
tag = '!ENV'
149+
tag_env = '!ENV'
149150

150151
# Pattern for environment variable: ${word}
151-
pattern = re.compile('.*?\${(\w+)}.*?')
152+
pattern_env = re.compile('.*?\${(\w+)}.*?')
152153

153-
yaml.SafeLoader.add_implicit_resolver(tag, pattern, None)
154+
yaml.SafeLoader.add_implicit_resolver(tag_env, pattern_env, None)
154155

155156
def constructor_env_variables(loader, node):
156157
"""
@@ -160,7 +161,7 @@ def constructor_env_variables(loader, node):
160161
:return: value of the environment variable
161162
"""
162163
value = loader.construct_scalar(node)
163-
match = pattern.findall(value)
164+
match = pattern_env.findall(value)
164165
if match:
165166
new_value = value
166167
for m in match:
@@ -169,7 +170,39 @@ def constructor_env_variables(loader, node):
169170
return new_value
170171
return value
171172

172-
yaml.SafeLoader.add_constructor(tag, constructor_env_variables)
173+
yaml.SafeLoader.add_constructor(tag_env, constructor_env_variables)
174+
175+
# Tag to indicate file pointed to by environment variable: !ENVFILE
176+
tag_env_file = '!ENVFILE'
177+
178+
# Pattern for environment variable: $(word)
179+
pattern_env_file = re.compile('.*?\$\((\w+)\).*?')
180+
181+
yaml.SafeLoader.add_implicit_resolver(tag_env_file,
182+
pattern_env_file, None)
183+
184+
def constructor_envfile_variables(loader, node):
185+
"""
186+
Extracts the environment variable from the node's value.
187+
:param yaml.Loader loader: the yaml loader
188+
:param node: the current node in the yaml
189+
:return: value read from file pointed to by environment variable
190+
"""
191+
value = loader.construct_scalar(node)
192+
match = pattern_env_file.findall(value)
193+
if match:
194+
new_value = value
195+
for m in match:
196+
path = os.environ.get(m, '')
197+
if os.path.exists(path):
198+
with open(path, 'r') as f:
199+
new_value = new_value.replace('$(' + m + ')',
200+
f.read().strip())
201+
return new_value
202+
return value
203+
204+
yaml.SafeLoader.add_constructor(tag_env_file,
205+
constructor_envfile_variables)
173206

174207
try:
175208
with open(os.path.abspath(config_file)) as f:

tests/satosa/test_satosa_config.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,12 @@ def test_can_substitute_from_environment_variable(self, monkeypatch):
8282
"proxy_conf_environment_test.yaml"))
8383

8484
assert config["COOKIE_STATE_NAME"] == 'oatmeal_raisin'
85+
86+
def test_can_substitute_from_environment_variable_file(self, monkeypatch):
87+
cookie_file = os.path.join(TEST_RESOURCE_BASE_PATH,
88+
'cookie_state_name')
89+
monkeypatch.setenv("SATOSA_COOKIE_STATE_NAME_FILE", cookie_file)
90+
config = SATOSAConfig(os.path.join(TEST_RESOURCE_BASE_PATH,
91+
"proxy_conf_environment_file_test.yaml"))
92+
93+
assert config["COOKIE_STATE_NAME"] == 'chocolate_chip'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
chocolate_chip
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
BASE: https://example.com
2+
3+
STATE_ENCRYPTION_KEY: state_encryption_key
4+
5+
INTERNAL_ATTRIBUTES: {"attributes": {}}
6+
7+
COOKIE_STATE_NAME: !ENVFILE $(SATOSA_COOKIE_STATE_NAME_FILE)
8+
9+
BACKEND_MODULES: []
10+
FRONTEND_MODULES: []

0 commit comments

Comments
 (0)