示例#1
0
    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))
示例#2
0
    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))
示例#3
0
    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)
示例#4
0
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
示例#5
0
 def db(self, mongodb_instance):
     return MongoWrapper(mongodb_instance.get_uri(), 'pyop', 'test')
示例#6
0
    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)
示例#7
0
    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)