def _create_provider(self, endpoint_baseurl): response_types_supported = self.config["provider"].get("response_types_supported", ["id_token"]) subject_types_supported = self.config["provider"].get("subject_types_supported", ["pairwise"]) scopes_supported = self.config["provider"].get("scopes_supported", ["openid"]) capabilities = { "issuer": self.base_url, "authorization_endpoint": "{}/{}".format(endpoint_baseurl, AuthorizationEndpoint.url), "jwks_uri": "{}/jwks".format(endpoint_baseurl), "response_types_supported": response_types_supported, "id_token_signing_alg_values_supported": [self.signing_key.alg], "response_modes_supported": ["fragment", "query"], "subject_types_supported": subject_types_supported, "claim_types_supported": ["normal"], "claims_parameter_supported": True, "claims_supported": [attribute_map["openid"][0] for attribute_map in self.internal_attributes["attributes"].values() if "openid" in attribute_map], "request_parameter_supported": False, "request_uri_parameter_supported": False, "scopes_supported": scopes_supported } if self.config["provider"].get("client_registration_supported", False): capabilities["registration_endpoint"] = "{}/{}".format(endpoint_baseurl, RegistrationEndpoint.url) authz_state = self._init_authorization_state() db_uri = self.config.get("db_uri") cdb = MongoWrapper(db_uri, "satosa", "clients") if db_uri else {} self.user_db = MongoWrapper(db_uri, "satosa", "authz_codes") if db_uri else {} self.provider = Provider(self.signing_key, capabilities, authz_state, cdb, Userinfo(self.user_db))
def authn_response(self, context, binding): """ Endpoint for the idp response :type context: satosa.context,Context :type binding: str :rtype: satosa.response.Response :param context: The current context :param binding: The saml binding type :return: response """ if not context.request["SAMLResponse"]: satosa_logging(logger, logging.DEBUG, "Missing Response for state", context.state) raise SATOSAAuthenticationError(context.state, "Missing Response") try: authn_response = self.sp.parse_authn_request_response( context.request["SAMLResponse"], binding, outstanding=self.outstanding_queries) except Exception as err: satosa_logging(logger, logging.DEBUG, "Failed to parse authn request for state", context.state, exc_info=True) raise SATOSAAuthenticationError( context.state, "Failed to parse authn request") from err if self.sp.config.getattr('allow_unsolicited', 'sp') is False: req_id = authn_response.in_response_to if req_id not in self.outstanding_queries: errmsg = "No request with id: {}".format(req_id), satosa_logging(logger, logging.DEBUG, errmsg, context.state) raise SATOSAAuthenticationError(context.state, errmsg) del self.outstanding_queries[req_id] # check if the relay_state matches the cookie state if context.state[ self.name]["relay_state"] != context.request["RelayState"]: satosa_logging(logger, logging.DEBUG, "State did not match relay state for state", context.state) raise SATOSAAuthenticationError(context.state, "State did not match relay state") db_uri = self.config.get("db_uri") if db_uri: consent_db = MongoWrapper(db_uri, "satosa", "consents") consent_db.pop(context.state[self.name]['relay_state'], None) del context.state[self.name] return self.auth_callback_func( context, self._translate_response(authn_response, context.state))
def _init_authorization_state(self): sub_hash_salt = self.config.get("sub_hash_salt", rndstr(16)) db_uri = self.config.get("db_uri") if db_uri: authz_code_db = MongoWrapper(db_uri, "satosa", "authz_codes") access_token_db = MongoWrapper(db_uri, "satosa", "access_tokens") refresh_token_db = MongoWrapper(db_uri, "satosa", "refresh_tokens") sub_db = MongoWrapper(db_uri, "satosa", "subject_identifiers") else: authz_code_db = None access_token_db = None refresh_token_db = None sub_db = None token_lifetimes = {k: self.config["provider"][k] for k in ["authorization_code_lifetime", "access_token_lifetime", "refresh_token_lifetime", "refresh_token_threshold"] if k in self.config["provider"]} return AuthorizationState(HashBasedSubjectIdentifierFactory(sub_hash_salt), authz_code_db, access_token_db, refresh_token_db, sub_db, **token_lifetimes)
def oidc_frontend_config(signing_key_path, mongodb_instance): data = { "module": "satosa.frontends.openid_connect.OpenIDConnectFrontend", "name": "OIDCFrontend", "config": { "issuer": "https://proxy-op.example.com", "signing_key_path": signing_key_path, "provider": {"response_types_supported": ["id_token"]}, "db_uri": mongodb_instance.get_uri() # use mongodb for integration testing } } # insert client in mongodb cdb = MongoWrapper(mongodb_instance.get_uri(), "satosa", "clients") cdb[CLIENT_ID] = { "redirect_uris": [REDIRECT_URI], "response_types": ["id_token"] } return data
def db(self, mongodb_instance): return MongoWrapper(mongodb_instance.get_uri(), 'pyop', 'test')
def __call__(self, environ, start_response, debug=False): path = environ.get('PATH_INFO', '').lstrip('/') if ".." in path or path == "": resp = NotFound("Couldn't find the page you asked for!") return resp(environ, start_response) context = Context() context.path = path # copy wsgi.input stream to allow it to be re-read later by satosa plugins # see: http://stackoverflow.com/questions/1783383/how-do-i-copy-wsgi-input-if-i-want-to-process-post-data-more-than-once content_length = int(environ.get('CONTENT_LENGTH', '0') or '0') body = io.BytesIO(environ['wsgi.input'].read(content_length)) environ['wsgi.input'] = body context.request = unpack_request(environ, content_length) environ['wsgi.input'].seek(0) ### rZone Code Start ### access_ip = environ['HTTP_X_FORWARDED_FOR'] if context.path == 'rz-api/client-info': try: resp_data = {} resp_data['status'] = 401 allow_ip = self.config['config']['rz_api']['allow_ip'] if access_ip not in allow_ip: resp = Response(message=json.dumps(resp_data)) return resp(environ, start_response) relay_state = context.request['relay_state'] db_uri = self.config['config']['db_uri'] client_db = MongoWrapper(db_uri, "satosa", "clients") consent_db = MongoWrapper(db_uri, "satosa", "consents") if relay_state not in consent_db: resp_data['status'] = 404 resp = Response(message=json.dumps(resp_data)) return resp(environ, start_response) resp_data['status'] = 201 consent_info = consent_db[relay_state] if consent_info["requester"] in client_db: consent_info['client_info'] = client_db[ consent_info["requester"]] resp_data['status'] = 200 resp_data['data'] = consent_info resp = Response(message=json.dumps(resp_data)) return resp(environ, start_response) except: e = sys.exc_info()[0] resp = Response(message='{"status": 500}') return resp(environ, start_response) ### rZone Code End ### context.cookie = environ.get("HTTP_COOKIE", "") context.request_authorization = environ.get("HTTP_AUTHORIZATION", "") try: resp = self.run(context) if isinstance(resp, Exception): raise resp return resp(environ, start_response) except SATOSANoBoundEndpointError: resp = NotFound("Couldn't find the page you asked for!") return resp(environ, start_response) except Exception as err: if type(err) != UnknownSystemEntity: logger.exception("%s" % err) if debug: raise resp = ServiceError("%s" % err) return resp(environ, start_response)
def authn_request(self, context, entity_id): """ Do an authorization request on idp with given entity id. This is the start of the authorization. :type context: satosa.context.Context :type entity_id: str :rtype: satosa.response.Response :param context: The current context :param entity_id: Target IDP entity id :return: response to the user agent """ # If IDP blacklisting is enabled and the selected IDP is blacklisted, # stop here if self.idp_blacklist_file: with open(self.idp_blacklist_file) as blacklist_file: blacklist_array = json.load(blacklist_file)['blacklist'] if entity_id in blacklist_array: satosa_logging( logger, logging.DEBUG, "IdP with EntityID {} is blacklisted".format( entity_id), context.state, exc_info=False) raise SATOSAAuthenticationError( context.state, "Selected IdP is blacklisted for this backend") kwargs = {} authn_context = self.construct_requested_authn_context(entity_id) if authn_context: kwargs['requested_authn_context'] = authn_context try: binding, destination = self.sp.pick_binding( "single_sign_on_service", None, "idpsso", entity_id=entity_id) satosa_logging( logger, logging.DEBUG, "binding: %s, destination: %s" % (binding, destination), context.state) acs_endp, response_binding = self.sp.config.getattr( "endpoints", "sp")["assertion_consumer_service"][0] req_id, req = self.sp.create_authn_request( destination, binding=response_binding, **kwargs) relay_state = util.rndstr() ht_args = self.sp.apply_binding(binding, "%s" % req, destination, relay_state=relay_state) satosa_logging(logger, logging.DEBUG, "ht_args: %s" % ht_args, context.state) except Exception as exc: satosa_logging(logger, logging.DEBUG, "Failed to construct the AuthnRequest for state", context.state, exc_info=True) raise SATOSAAuthenticationError( context.state, "Failed to construct the AuthnRequest") from exc if self.sp.config.getattr('allow_unsolicited', 'sp') is False: if req_id in self.outstanding_queries: errmsg = "Request with duplicate id {}".format(req_id) satosa_logging(logger, logging.DEBUG, errmsg, context.state) raise SATOSAAuthenticationError(context.state, errmsg) self.outstanding_queries[req_id] = req context.state[self.name] = {"relay_state": relay_state} ### rZone Code Start ### requested_attributes = [] for claim_name in self.requested_claims: if claim_name in self.internal_attributes['attributes']: if 'saml' in self.internal_attributes['attributes'][ claim_name]: for saml_attr in self.internal_attributes['attributes'][ claim_name]['saml']: requested_attributes.append(saml_attr) db_uri = self.config.get("db_uri") if db_uri: consent_db = MongoWrapper(db_uri, "satosa", "consents") consent_info = {} consent_info['relay_state'] = relay_state consent_info['requester'] = self.internal_req.requester consent_info['requested_attributes'] = requested_attributes consent_db[relay_state] = consent_info ''' logger.info('======= proin:satosa:samlbackend =========') logger.info('proin:satosa:samlbackend:attribute ' + str(requested_attributes)) logger.info('proin:satosa:samlbackend:requester ' + self.internal_req.requester) logger.info('proin:satosa:samlbackend:requester_name ' + self.internal_req.requester_name[0]['text']) logger.info('proin:satosa:samlbackend:relay ' + relay_state) ''' ### rZone Code End ### return make_saml_response(binding, ht_args)