Skip to content

Commit ce9cd5d

Browse files
committed
feat: Decide which backend to use, detecting the entityid to which the authn request is request is referred
1 parent 1def998 commit ce9cd5d

File tree

4 files changed

+90
-0
lines changed

4 files changed

+90
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module: satosa.micro_services.custom_routing.DecideBackendByTarget
2+
name: TargetRouter
3+
config:
4+
target_mapping:
5+
"http://idpspid.testunical.it:8088": "spidSaml2" # map SAML entity with entity id 'target_id' to backend name
6+
"http://eidas.testunical.it:8081/saml2/metadata": "eidasSaml2"

src/satosa/exception.py

+7
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ class SATOSACriticalError(SATOSAError):
3131
pass
3232

3333

34+
class SATOSABackendNotFoundError(SATOSAError):
35+
"""
36+
SATOSA Backend not existent/not found
37+
"""
38+
pass
39+
40+
3441
class SATOSAUnknownError(SATOSAError):
3542
"""
3643
SATOSA unknown error

src/satosa/micro_services/custom_routing.py

+62
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,73 @@
55
from .base import RequestMicroService
66
from ..exception import SATOSAConfigurationError
77
from ..exception import SATOSAError
8+
from ..exception import SATOSABackendNotFoundError
89

910

1011
logger = logging.getLogger(__name__)
1112

1213

14+
class DecideBackendByTarget(RequestMicroService):
15+
"""
16+
Select which backend should be used based on who is the SAML IDP
17+
"""
18+
19+
def __init__(self, config, *args, **kwargs):
20+
"""
21+
Constructor.
22+
:param config: mapping from requester identifier to
23+
backend module name under the key 'requester_mapping'
24+
:type config: Dict[str, Dict[str, str]]
25+
"""
26+
super().__init__(*args, **kwargs)
27+
self.target_mapping = config['target_mapping']
28+
29+
30+
def get_backend_by_endpoint_path(self, context, native_backend,
31+
backends):
32+
"""
33+
Returns a new path and target_backend according to its maps
34+
35+
:type context: satosa.context.Context
36+
:rtype: ((satosa.context.Context, Any) -> Any, Any)
37+
38+
:param context: The request context
39+
:param native_backed: the backed that the proxy normally have been used
40+
:param backends: list of all the backend configured in the proxy
41+
42+
:return: tuple or None
43+
"""
44+
entity_id = context.request.get('entityID')
45+
tr_backend = self.target_mapping.get(entity_id)
46+
if not entity_id:
47+
return
48+
if entity_id not in self.target_mapping.keys():
49+
return
50+
if not tr_backend:
51+
return
52+
53+
if not backends.get(tr_backend):
54+
raise SATOSABackendNotFoundError(
55+
f"'{tr_backend}' not found in proxy_conf.yaml"
56+
)
57+
58+
if not backends.get(tr_backend):
59+
raise SATOSABackendNotFoundError(
60+
f"'{tr_backend}' not found in proxy_conf.yaml"
61+
)
62+
63+
tr_path = context.path.replace(native_backend, tr_backend)
64+
for endpoint in backends[tr_backend]['endpoints']:
65+
# remove regex trailing chars
66+
if tr_path == endpoint[0].strip('^').strip('$'):
67+
msg = (f'Found DecideBackendByTarget ({self.name} microservice) '
68+
f'redirecting {entity_id} from {native_backend} '
69+
f'backend to {tr_backend}')
70+
logger.info(msg)
71+
return (tr_backend, tr_path)
72+
return
73+
74+
1375
class DecideBackendByRequester(RequestMicroService):
1476
"""
1577
Select which backend should be used based on who the requester is.

src/satosa/routing.py

+15
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,21 @@ def endpoint_routing(self, context):
158158
path_split = context.path.split("/")
159159
backend = path_split[0]
160160

161+
# Target router interception
162+
trouter_microservice_name = 'TargetRouter'
163+
if all((context.request,
164+
context.request.get('entityID'),
165+
(trouter_microservice_name in self.micro_services))):
166+
tr_microservice = self.micro_services[trouter_microservice_name]['instance']
167+
tr_result = tr_microservice.get_backend_by_endpoint_path(
168+
context, backend, self.backends
169+
)
170+
if tr_result:
171+
backend, context.path = tr_result
172+
context.target_backend = backend
173+
return self._find_registered_backend_endpoint(context)
174+
# end Target router interception
175+
161176
if backend in self.backends:
162177
context.target_backend = backend
163178
else:

0 commit comments

Comments
 (0)