Skip to content

Commit 8ff3572

Browse files
committed
feat: DecideBackedByTarget microservice
1 parent ba86be2 commit 8ff3572

File tree

2 files changed

+72
-0
lines changed

2 files changed

+72
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module: satosa.micro_services.custom_routing.DecideBackendByTarget
2+
name: TargetRouter
3+
config:
4+
5+
# the regex that will intercept http requests to be handled with this microservice
6+
endpoint_path: ".*/disco"
7+
8+
target_mapping:
9+
"http://idpspid.testunical.it:8088": "spidSaml2" # map SAML entity with entity id 'target_id' to backend name
10+
"http://eidas.testunical.it:8081/saml2/metadata": "eidasSaml2"

src/satosa/micro_services/custom_routing.py

+62
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from base64 import urlsafe_b64encode
33

44
from satosa.context import Context
5+
from satosa.internal import InternalData
6+
57
from .base import RequestMicroService
68
from ..exception import SATOSAConfigurationError
79
from ..exception import SATOSAError
@@ -10,6 +12,66 @@
1012
logger = logging.getLogger(__name__)
1113

1214

15+
class DecideBackendByTarget(RequestMicroService):
16+
"""
17+
Select which backend should be used based on who is the SAML IDP
18+
"""
19+
20+
def __init__(self, config, *args, **kwargs):
21+
"""
22+
Constructor.
23+
:param config: microservice configuration loaded from yaml file
24+
:type config: Dict[str, Dict[str, str]]
25+
"""
26+
super().__init__(*args, **kwargs)
27+
self.target_mapping = config['target_mapping']
28+
self.endpoint_path = config['endpoint_path']
29+
30+
def register_endpoints(self):
31+
"""
32+
URL mapping of additional endpoints this micro service needs to register for callbacks.
33+
34+
Example of a mapping from the url path '/callback' to the callback() method of a micro service:
35+
reg_endp = [
36+
("^/callback1$", self.callback),
37+
]
38+
39+
:rtype List[Tuple[str, Callable[[satosa.context.Context, Any], satosa.response.Response]]]
40+
41+
:return: A list with functions and args bound to a specific endpoint url,
42+
[(regexp, Callable[[satosa.context.Context], satosa.response.Response]), ...]
43+
"""
44+
45+
# this intercepts disco response
46+
return [
47+
(self.endpoint_path , self.backend_by_entityid),
48+
]
49+
50+
def backend_by_entityid(self, context):
51+
entity_id = context.request.get('entityID')
52+
tr_backend = self.target_mapping.get(entity_id)
53+
54+
if not all((context.request,
55+
entity_id,
56+
entity_id in self.target_mapping.keys(),
57+
tr_backend)):
58+
return
59+
60+
context.internal_data['target_entity_id'] = entity_id
61+
context.target_frontend = context.state['ROUTER']
62+
63+
data_serialized = context.state.get(self.name, {}).get("internal", {})
64+
data = InternalData.from_dict(data_serialized)
65+
66+
native_backend = context.target_backend
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+
context.target_backend = tr_backend
72+
return super().process(context, data)
73+
74+
1375
class DecideBackendByRequester(RequestMicroService):
1476
"""
1577
Select which backend should be used based on who the requester is.

0 commit comments

Comments
 (0)