-
Notifications
You must be signed in to change notification settings - Fork 124
Anatomy of a response micro service
Ivan Kanakarakis edited this page Mar 13, 2020
·
11 revisions
A micro-service has configuration and code. The configuration is given to the micro-service on initialization. Any validation on the configuration should be done at this point. The micro-service is loaded and awaits execution.
When the right time comes, the micro-service is invoked through the process()
function. The process()
function receives two parameters: the context
of the current request, and data
which reflects the internal data representation of the protocol information, as transformed by the corresponding frontend or backend.
The micro-service (most of the time) will add/remove/change data.attributes
and in the end it will return the result for the next micro-service to work upon.
module: example.satosa.micro_services.micro_service_module.NameOfMicroservice
name: An example micro-service skeleton
config:
capitalize_name: True
"""A micro-service example."""
import logging
import satosa
import satosa.logging_util as lu
from satosa.micro_services.base import ResponseMicroService
logger = logging.getLogger(__name__)
class NameOfMicroservice(ResponseMicroService):
"""
A micro-service to show an example skeleton.
Example configuration:
```yaml
module: python.path.to.the.class.NameOfMicroservice
name: An example micro-service skeleton
config:
capitalize_name: True
```
"""
def __init__(self, config, *args, **kwargs):
super().__init__(*args, **kwargs)
self.capitalize_name = config.get("capitalize_name", False)
log_debug("initialized the micro-service")
def process(
self, context: satosa.context.Context, data: satosa.internal.InternalData
):
log_debug("running the micro-service", context)
# do things with data.attributes
if self.capitalize_name:
data.attributes["name"] = [
value.upper() for value in data.attributes.get("name", [])
]
# log a message
message = "name has been capitilized"
log_info(message, context)
log_debug("end of the micro-service", context)
# return updated context and data
return super().process(context, data)
# some logging helpers to avoid duplication
def log_debug(msg, context=None):
_log(logging.DEBUG, msg, context)
def log_info(msg, context=None):
_log(logging.INFO, msg, context)
def _log(loglevel, msg, context):
state = context.state if context else None
session_id = lu.get_session_id(state)
line = lu.LOG_FMT.format(id=session_id, message=msg)
logger.log(loglevel, line)
# type: satosa.internal.InternalData
data = {
# type: satosa.internal.AuthenticationInformation
# This part holds the authentication information
# namely, the authentication context classes (ie, the LoA reference)
# and the issuer of the given identity (ie, the IdP entity-id)
"auth_info": {
"auth_class_ref": "urn:oasis:names:tc:SAML:2.0:ac:classes:Password",
"timestamp": "2020-02-22T19:30:04Z",
"issuer": "https://www.rediris.es/sir/umaidp",
},
# the requester of the authentication; this is typically the SP (or RP) entity-id
"requester": "https://example.org/saml-sp/metadata.xml",
"requester_name": [{"text": None, "lang": "en"}],
# the subject identifier as expressed in different protocols, along with its type or format.
# this will match `NameID` for SAML2 and `sub` for OIDC.
"subject_id": "69e83a116ed953279999d4463541c2799795c816",
"subject_type": "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
# the attributes of the subject as expressed in different protocols.
# this will be a representation of claims for OIDC,
# or attribute statements of an assertion for SAML2.
"attributes": {
"edupersontargetedid": ["04e8192d48a040f3ef495999958908f8aa10b4a5"],
"displayname": ["Somename Somesurname"],
"givenname": ["Somename"],
"mail": ["[email protected]"],
"name": ["Somename"],
"surname": ["Somesurname"],
"epsa": ["[email protected]", "[email protected]"],
"eppn": ["[email protected]"],
"spuc": [
"urn:schac:personalUniqueCode:es:rediris:sir:mbid:{sha1}0c938d124632017100980299997b1ab174789657",
"urn:schac:personalUniqueCode:es:uma:CAU:id:822",
"urn:schac:personalUniqueCode:es:uma:ESC:code:a98b1a8c-9215-11e9-8545-000077349997",
"urn:schac:personalUniqueCode:es:uma:codUni:06100004X",
],
},
# this has been added by another micro-service; namely metainfo
# the role of that micro-service is to collect metadata information about entities
# and present it in a unified way.
# other micro-services can lookup the metadata of an entity using this structure.
"metadata": {
"https://www.rediris.es/sir/umaidp": {
"display_name": "University of Malaga",
"privacy_statement": None,
"contacts": [
{
"contact_type": "technical",
"given_name": "SIR helpdesk",
"email_address": ["mailto:[email protected]"],
},
{
"contact_type": "other",
"given_name": "RedIRIS SIRTFI-CSIRT Team",
"email_address": ["mailto:[email protected]"],
},
],
"entity_categories": [],
"supported_entity_categories": [
"http://refeds.org/category/research-and-scholarship"
],
"assurance_certifications": ["https://refeds.org/sirtfi"],
},
"https://example.org/saml-sp/metadata.xml": {
"display_name": None,
"privacy_statement": None,
"contacts": [],
"entity_categories": [],
"supported_entity_categories": [],
"assurance_certifications": [],
},
}
}
context = {
"cookie": 'SATOSA_PROXY_STATE="..."',
"internal_data": {
"metadata_store": <saml2.mdstore.MetadataStore object at 0x7fc60e32cb70>
},
"request": None,
"request_authorization": "",
# type: satosa.state.State
"state": {
"ROUTER": "Saml2IDP",
"SATOSA_BASE": {"requester": "..."},
"Saml2IDP": {
"relay_state": "https://example.org/authenticate?as=some-sp",
"resp_args": {
"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
"destination": "https://example.org/saml-sp/saml2-acs",
"in_response_to": "_e923792fde97aa0b6bc82999cba5274a61eae4b96c",
"name_id_policy": """<ns0:NameIDPolicy xmlns:ns0="urn:oasis:names:tc:SAML:2.0:protocol" AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>""",
"sp_entity_id": "...",
},
},
"memorized_idp": "...",
},
"target_backend": "saml2sp",
"target_frontend": None,
"target_micro_service": None,
}