Skip to content

Commit fbfd54b

Browse files
Revert "First commit of the SAMLUnsolicitedFrontend class"
1 parent 8c9d380 commit fbfd54b

File tree

1 file changed

+1
-224
lines changed

1 file changed

+1
-224
lines changed

src/satosa/frontends/saml2.py

Lines changed: 1 addition & 224 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import re
99
from base64 import urlsafe_b64decode
1010
from base64 import urlsafe_b64encode
11-
from base64 import b64encode
1211
from urllib.parse import quote
1312
from urllib.parse import quote_plus
1413
from urllib.parse import unquote
@@ -17,9 +16,7 @@
1716
from http.cookies import SimpleCookie
1817

1918
from saml2 import SAMLError, xmldsig
20-
from saml2 import BINDING_HTTP_POST
21-
from saml2.client_base import Base
22-
from saml2.config import IdPConfig, SPConfig
19+
from saml2.config import IdPConfig
2320
from saml2.extension.ui import NAMESPACE as UI_NAMESPACE
2421
from saml2.metadata import create_metadata_string
2522
from saml2.saml import NameID
@@ -31,7 +28,6 @@
3128
from saml2.server import Server
3229

3330
from satosa.base import SAMLBaseModule
34-
from satosa.backends.saml2 import SAMLBackend
3531
from satosa.context import Context
3632
from .base import FrontendModule
3733
from ..logging_util import satosa_logging
@@ -1018,222 +1014,3 @@ def _register_endpoints(self, backend_names):
10181014
logger.debug("Adding mapping {}".format(mapping))
10191015

10201016
return url_to_callable_mappings
1021-
1022-
1023-
class SAMLUnsolicitedFrontend(SAMLFrontend):
1024-
"""
1025-
Frontend module that provides all of the functionality of the base class
1026-
SAMLFrontend but also provides a proprietary endpoint for initiating
1027-
unsolicted SAML flows. The unsolicited SAML flows are not part of any
1028-
SAML standard.
1029-
"""
1030-
1031-
KEY_ENDPOINT = "endpoint"
1032-
KEY_DISCO_URL_WHITE = "discovery_service_url_whitelist"
1033-
KEY_DISCO_POLICY_WHITE = "discovery_service_policy_whitelist"
1034-
KEY_QUERY_IDP = "authId"
1035-
KEY_QUERY_SP = "providerId"
1036-
KEY_QUERY_ACS = "shire"
1037-
KEY_QUERY_RELAY = "target"
1038-
KEY_QUERY_DISCO_URL = "discoveryURL"
1039-
KEY_QUERY_DISCO_POLICY = "discoveryPolicy"
1040-
KEY_SAML_DISCOVERY_SERVICE_URL = SAMLBackend.KEY_SAML_DISCOVERY_SERVICE_URL
1041-
KEY_SAML_DISCOVERY_SERVICE_POLICY = SAMLBackend.KEY_SAML_DISCOVERY_SERVICE_POLICY
1042-
KEY_UNSOLICITED = "unsolicited"
1043-
1044-
def __init__(
1045-
self, auth_req_callback_func, internal_attributes, config, base_url, name
1046-
):
1047-
super().__init__(
1048-
auth_req_callback_func, internal_attributes, config, base_url, name
1049-
)
1050-
1051-
def register_endpoints(self, backend_names):
1052-
"""
1053-
See super class
1054-
satosa.frontends.saml2.SAMLFrontend#register_endpoints
1055-
1056-
:type providers: list[str]
1057-
:rtype: list[(str, ((satosa.context.Context, Any)
1058-
-> satosa.response.Response, Any))]
1059-
:param providers: A list of backend providers
1060-
:return: A list of endpoint/method pairs
1061-
"""
1062-
url_map = super().register_endpoints(backend_names)
1063-
1064-
path = urlparse(self.config[self.KEY_UNSOLICITED].get(self.KEY_ENDPOINT)).path
1065-
1066-
for backend in backend_names:
1067-
pat = "(^{})/{}$".format(backend, path)
1068-
url_map.append((pat, self.unsolicited_endpoint))
1069-
1070-
logger.debug("URL maps to be registered are {}".format(url_map))
1071-
1072-
return url_map
1073-
1074-
def unsolicited_endpoint(self, context):
1075-
"""
1076-
Endpoint to process unsolicited SAML flows. The unsolicited flows
1077-
are proprietary and not defined as part of any SAML standard.
1078-
1079-
:type context: satosa.context.Context
1080-
:rtype: satosa.response.Response
1081-
1082-
:param context: The current context
1083-
:return: response
1084-
"""
1085-
request = context.request
1086-
1087-
target_idp_entity_id = request.get(self.KEY_QUERY_IDP, None)
1088-
target_sp_entity_id = request.get(self.KEY_QUERY_SP, None)
1089-
target_sp_acs_url = request.get(self.KEY_QUERY_ACS, None)
1090-
target_sp_relay_state_url = request.get(self.KEY_QUERY_RELAY, None)
1091-
requested_disco_url = request.get(self.KEY_QUERY_DISCO_URL, None)
1092-
requested_disco_policy = request.get(self.KEY_QUERY_DISCO_POLICY, None)
1093-
1094-
logger.debug(
1095-
"Unsolicited target authenticating IdP is {}".format(target_idp_entity_id)
1096-
)
1097-
logger.debug("Unsolicited target SP is {}".format(target_sp_entity_id))
1098-
logger.debug("Unsolicited ACS URL is {}".format(target_sp_acs_url))
1099-
logger.debug("Unsolicited relay state is {}".format(target_sp_relay_state_url))
1100-
logger.debug("Unsolicted discovery URL is {}".format(requested_disco_url))
1101-
logger.debug("Unsolicted discovery policy is {}".format(requested_disco_policy))
1102-
1103-
# We only proceed with known federated SPs.
1104-
try:
1105-
target_sp_metadata = self.idp.metadata[target_sp_entity_id]
1106-
except KeyError:
1107-
msg = "Target SP with entityID {} is unknown in metadata"
1108-
msg = msg.format(target_sp_entity_id)
1109-
satosa_logging(logger, logging.ERROR, msg, context.state)
1110-
raise SATOSAError(msg)
1111-
1112-
# The SP ACS URL if input must match one from the trusted metadata.
1113-
# We assume the SP only has one SPSSODescriptor element in metadata.
1114-
acs_ob_list = target_sp_metadata.get("spsso_descriptor", [{}])[0].get(
1115-
"assertion_consumer_service", [{}]
1116-
)
1117-
acs_locations = [acs_ob["location"] for acs_ob in acs_ob_list]
1118-
1119-
if target_sp_acs_url:
1120-
if target_sp_acs_url not in acs_locations:
1121-
msg = "Target ACS URL {} not allowed"
1122-
msg = msg.format(target_sp_acs_url)
1123-
satosa_logging(logger, logging.ERROR, msg, context.state)
1124-
raise SATOSAError(msg)
1125-
else:
1126-
for acs_ob in acs_ob_list:
1127-
# We assume the SP has HTTP_POST binding and we simply
1128-
# take the first one we find.
1129-
if acs_ob["binding"] == BINDING_HTTP_POST:
1130-
target_sp_acs_url = acs_ob["location"]
1131-
logger.debug(
1132-
"Unsolicited found SP ACS URL {}".format(target_sp_acs_url)
1133-
)
1134-
break
1135-
1136-
if not target_sp_acs_url:
1137-
msg = "No ACS for SP with entityID {}".format(target_sp_entity_id)
1138-
satosa_logging(logger, logging.ERROR, msg, context.state)
1139-
raise SATOSAError(msg)
1140-
1141-
# If provided the exact scheme, host, and port for relay state URL
1142-
# must match that of the target SP ACS URL.
1143-
if target_sp_relay_state_url:
1144-
target = urlparse(target_sp_relay_state_url)
1145-
acs = urlparse(target_sp_acs_url)
1146-
if not (
1147-
target.scheme == acs.scheme
1148-
and target.netloc == acs.netloc
1149-
and target.port == acs.port
1150-
):
1151-
msg = "RelayState {} is not permitted"
1152-
msg = msg.format(target_sp_relay_state_url)
1153-
satosa_logging(logger, logging.ERROR, msg, context.state)
1154-
raise SATOSAError(msg)
1155-
1156-
# Create a temporary SP configuration to represent the target SP.
1157-
acs = [[target_sp_acs_url, BINDING_HTTP_POST]]
1158-
sp_config_dict = {
1159-
"entityid": target_sp_entity_id,
1160-
"service": {"sp": {"endpoints": {"assertion_consumer_service": acs}}},
1161-
}
1162-
sp_config = SPConfig().load(sp_config_dict, False)
1163-
1164-
# Create a temporary SP object and use it to create a authn request
1165-
# with a destination of our own SingleSignOnService location with
1166-
# HTTP-POST binding.
1167-
target_sp = Base(sp_config)
1168-
1169-
destination = None
1170-
endpoints = self.idp.config.getattr("endpoints")
1171-
sso_service_list = endpoints["single_sign_on_service"]
1172-
for location, binding in sso_service_list:
1173-
if binding == BINDING_HTTP_POST:
1174-
destination = location
1175-
break
1176-
1177-
if not destination:
1178-
msg = (
1179-
"Could not determine location for SingleSignOnService "
1180-
"with HTTP-POST binding"
1181-
)
1182-
satosa_logging(logger, logging.ERROR, msg, context.state)
1183-
raise SATOSAError(msg)
1184-
1185-
logger.debug("Unsolicited using destination {}".format(destination))
1186-
1187-
req_id, authn_request = target_sp.create_authn_request(destination)
1188-
1189-
# Convert the authn request object to an encoded set of bytes.
1190-
authn_request_str = "{}".format(authn_request)
1191-
logger.debug("Unsolicted authn request is {}".format(authn_request_str))
1192-
authn_request_bytes = authn_request_str.encode("utf-8")
1193-
authn_request_encoded = b64encode(authn_request_bytes)
1194-
1195-
# Add the authn request to the context as if it arrived through
1196-
# an endpoint.
1197-
context.request["SAMLRequest"] = authn_request_encoded
1198-
1199-
# Add the relay state to the context if provided.
1200-
if target_sp_relay_state_url:
1201-
context.request["RelayState"] = target_sp_relay_state_url
1202-
1203-
# If provided and is whitelisted set the discovery service to use.
1204-
if requested_disco_url:
1205-
allowed = self.config[self.KEY_UNSOLICITED].get(self.KEY_DISCO_URL_WHITE)
1206-
if requested_disco_url not in allowed:
1207-
msg = "Discovery service URL {} not allowed"
1208-
msg = msg.format(requested_disco_url)
1209-
satosa_logging(logger, logging.ERROR, msg, context.state)
1210-
raise SATOSAError(msg)
1211-
1212-
context.decorate(self.KEY_SAML_DISCOVERY_SERVICE_URL, requested_disco_url)
1213-
1214-
# If provided and is whitelisted set the discovery policy to use.
1215-
if requested_disco_policy:
1216-
allowed = self.config[self.KEY_UNSOLICITED].get(self.KEY_DISCO_POLICY_WHITE)
1217-
if requested_disco_policy not in allowed:
1218-
msg = "Discovery service policy {} not allowed"
1219-
msg = msg.format(requested_disco_policy)
1220-
satosa_logging(logger, logging.ERROR, msg, context.state)
1221-
raise SATOSAError(msg)
1222-
1223-
context.decorate(
1224-
self.KEY_SAML_DISCOVERY_SERVICE_POLICY, requested_disco_policy
1225-
)
1226-
1227-
# If provided and known in the SAML metadata set the entityID for
1228-
# the IdP to use for authentication.
1229-
if target_idp_entity_id:
1230-
if target_idp_entity_id in self.idp.metadata:
1231-
context.decorate(Context.KEY_TARGET_ENTITYID, target_idp_entity_id)
1232-
else:
1233-
msg = "Target IdP with entityID {} is unknown in metadata"
1234-
msg = msg.format(target_idp_entity_id)
1235-
satosa_logging(logger, logging.ERROR, msg, context.state)
1236-
raise SATOSAError(msg)
1237-
1238-
# Handle the authn request use the base class.
1239-
return self._handle_authn_request(context, BINDING_HTTP_POST, self.idp)

0 commit comments

Comments
 (0)