def build_links(self, request=None): links = {} if request is not None: links["self"] = request.build_absolute_uri(request.path) page = self._current_page if page is not None: if page.has_previous(): u = urlparse(links["self"]) q = parse_qs(u.query) q["page[number]"] = str(page.previous_page_number()) links["prev"] = ParseResult( u.scheme, u.netloc, u.path, u.params, urlencode(q), u.fragment, ).geturl() if page.has_next(): u = urlparse(links["self"]) q = parse_qs(u.query) q["page[number]"] = str(page.next_page_number()) links["next"] = ParseResult( u.scheme, u.netloc, u.path, u.params, urlencode(q), u.fragment, ).geturl() return links
def test__get_request_if_http_method_is_post(self): attr_ = {'user_api_key': ['spam'], 'developer_api_key': ['ham']} for api_method, http_method in DisqusClient.METHODS.items(): if http_method == "POST": url = self.client.api_url % api_method request_params = self.client._get_request(url, http_method, **self.attr) request_no_params = self.client._get_request(url, http_method) self.assertEqual(request_params.get_host(), 'disqus.com') self.assertEqual(request_no_params.get_host(), 'disqus.com') self.assertEqual(request_params.get_method(), http_method) self.assertEqual(request_no_params.get_method(), http_method) qs_params = parse_qs(request_params.data) qs_no_params = parse_qs(request_no_params.data) self.assertEqual(qs_params, attr_) self.assertEqual(qs_no_params, {})
def build_links(self, request=None): links = {} if request is not None: if hasattr(request, "build_absolute_uri"): links["self"] = request.build_absolute_uri(request.path) else: links["self"] = request.path page = self._current_page if page is not None: if page.has_previous(): u = urlparse(links["self"]) q = parse_qs(u.query) q["page[number]"] = str(page.previous_page_number()) links["prev"] = ParseResult( u.scheme, u.netloc, u.path, u.params, urlencode(q), u.fragment, ).geturl() if page.has_next(): u = urlparse(links["self"]) q = parse_qs(u.query) q["page[number]"] = str(page.next_page_number()) links["next"] = ParseResult( u.scheme, u.netloc, u.path, u.params, urlencode(q), u.fragment, ).geturl() return links
def test_export_url_tag(self): template = Template('{% load django_tables2 %}{% export_url "csv" %}') html = template.render(Context({"request": build_request("?q=foo")})) self.assertEqual(dict(parse_qs(html[1:])), dict(parse_qs("q=foo&_export=csv"))) # using a template context variable template = Template("{% load django_tables2 %}{% export_url format %}") html = template.render(Context({"request": build_request("?q=foo"), "format": "xls"})) self.assertEqual(dict(parse_qs(html[1:])), dict(parse_qs("q=foo&_export=xls")))
def test_export_url_tag(self): template = Template('{% load django_tables2 %}{% export_url "csv" %}') html = template.render(Context({'request': build_request('?q=foo')})) self.assertEqual(dict(parse_qs(html[1:])), dict(parse_qs('q=foo&_export=csv'))) # using a template context variable template = Template('{% load django_tables2 %}{% export_url format %}') html = template.render(Context({'request': build_request('?q=foo'), 'format': 'xls'})) self.assertEqual(dict(parse_qs(html[1:])), dict(parse_qs('q=foo&_export=xls')))
def test_export_url_tag(self): class View(ExportMixin): export_trigger_param = "_do_export" template = Template('{% load django_tables2 %}{% export_url "csv" %}') html = template.render(Context({"request": build_request("?q=foo"), "view": View()})) self.assertEqual(dict(parse_qs(html[1:])), dict(parse_qs("q=foo&_do_export=csv"))) # using a template context variable and a view template = Template("{% load django_tables2 %}{% export_url format %}") html = template.render( Context({"request": build_request("?q=foo"), "format": "xls", "view": View()}) ) self.assertEqual(dict(parse_qs(html[1:])), dict(parse_qs("q=foo&_do_export=xls"))) # using a template context variable template = Template("{% load django_tables2 %}{% export_url format %}") html = template.render(Context({"request": build_request("?q=foo"), "format": "xls"})) self.assertEqual(dict(parse_qs(html[1:])), dict(parse_qs("q=foo&_export=xls"))) # using a template context and change export parameter template = Template('{% load django_tables2 %}{% export_url "xls" "_other_export_param" %}') html = template.render(Context({"request": build_request("?q=foo"), "format": "xls"})) self.assertEqual( dict(parse_qs(html[1:])), dict(parse_qs("q=foo&_other_export_param=xls")) )
def test_login_one_idp(self): # monkey patch SAML configuration settings.SAML_CONFIG = conf.create_conf( sp_host='sp.example.com', idp_hosts=['idp.example.com'], metadata_file='remote_metadata_one_idp.xml', ) response = self.client.get(reverse('saml2_login')) self.assertEquals(response.status_code, 302) location = response['Location'] url = urlparse(location) self.assertEquals(url.hostname, 'idp.example.com') self.assertEquals(url.path, '/simplesaml/saml2/idp/SSOService.php') params = parse_qs(url.query) self.assert_('SAMLRequest' in params) self.assert_('RelayState' in params) saml_request = params['SAMLRequest'][0] if PY_VERSION < (2, 7): expected_request = """<?xml version='1.0' encoding='UTF-8'?> <samlp:AuthnRequest AssertionConsumerServiceURL="http://sp.example.com/saml2/acs/" Destination="https://idp.example.com/simplesaml/saml2/idp/SSOService.php" ID="XXXXXXXXXXXXXXXXXXXXXX" IssueInstant="2010-01-01T00:00:00Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">http://sp.example.com/saml2/metadata/</saml:Issuer><samlp:NameIDPolicy AllowCreate="false" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" /></samlp:AuthnRequest>""" elif PY_VERSION < (3, ): expected_request = """<?xml version='1.0' encoding='UTF-8'?> <samlp:AuthnRequest xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" AssertionConsumerServiceURL="http://sp.example.com/saml2/acs/" Destination="https://idp.example.com/simplesaml/saml2/idp/SSOService.php" ID="XXXXXXXXXXXXXXXXXXXXXX" IssueInstant="2010-01-01T00:00:00Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://sp.example.com/saml2/metadata/</saml:Issuer><samlp:NameIDPolicy AllowCreate="false" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" /></samlp:AuthnRequest>""" else: expected_request = """<samlp:AuthnRequest xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" AssertionConsumerServiceURL="http://sp.example.com/saml2/acs/" Destination="https://idp.example.com/simplesaml/saml2/idp/SSOService.php" ID="XXXXXXXXXXXXXXXXXXXXXX" IssueInstant="2010-01-01T00:00:00Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://sp.example.com/saml2/metadata/</saml:Issuer><samlp:NameIDPolicy AllowCreate="false" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" /></samlp:AuthnRequest>""" self.assertSAMLRequestsEquals( decode_base64_and_inflate(saml_request).decode('utf-8'), expected_request) # if we set a next arg in the login view, it is preserverd # in the RelayState argument next = '/another-view/' response = self.client.get(reverse('saml2_login'), {'next': next}) self.assertEquals(response.status_code, 302) location = response['Location'] url = urlparse(location) self.assertEquals(url.hostname, 'idp.example.com') self.assertEquals(url.path, '/simplesaml/saml2/idp/SSOService.php') params = parse_qs(url.query) self.assert_('SAMLRequest' in params) self.assert_('RelayState' in params) self.assertEquals(params['RelayState'][0], next)
def test_login_one_idp(self): # monkey patch SAML configuration settings.SAML_CONFIG = conf.create_conf( sp_host='sp.example.com', idp_hosts=['idp.example.com'], metadata_file='remote_metadata_one_idp.xml', ) response = self.client.get(reverse('saml2_login')) self.assertEquals(response.status_code, 302) location = response['Location'] url = urlparse(location) self.assertEquals(url.hostname, 'idp.example.com') self.assertEquals(url.path, '/simplesaml/saml2/idp/SSOService.php') params = parse_qs(url.query) self.assert_('SAMLRequest' in params) self.assert_('RelayState' in params) saml_request = params['SAMLRequest'][0] if PY_VERSION < (2, 7): expected_request = """<?xml version='1.0' encoding='UTF-8'?> <samlp:AuthnRequest AssertionConsumerServiceURL="http://sp.example.com/saml2/acs/" Destination="https://idp.example.com/simplesaml/saml2/idp/SSOService.php" ID="XXXXXXXXXXXXXXXXXXXXXX" IssueInstant="2010-01-01T00:00:00Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">http://sp.example.com/saml2/metadata/</saml:Issuer><samlp:NameIDPolicy AllowCreate="false" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" /></samlp:AuthnRequest>""" elif PY_VERSION < (3,): expected_request = """<?xml version='1.0' encoding='UTF-8'?> <samlp:AuthnRequest xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" AssertionConsumerServiceURL="http://sp.example.com/saml2/acs/" Destination="https://idp.example.com/simplesaml/saml2/idp/SSOService.php" ID="XXXXXXXXXXXXXXXXXXXXXX" IssueInstant="2010-01-01T00:00:00Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://sp.example.com/saml2/metadata/</saml:Issuer><samlp:NameIDPolicy AllowCreate="false" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" /></samlp:AuthnRequest>""" else: expected_request = """<samlp:AuthnRequest xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" AssertionConsumerServiceURL="http://sp.example.com/saml2/acs/" Destination="https://idp.example.com/simplesaml/saml2/idp/SSOService.php" ID="XXXXXXXXXXXXXXXXXXXXXX" IssueInstant="2010-01-01T00:00:00Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Version="2.0"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://sp.example.com/saml2/metadata/</saml:Issuer><samlp:NameIDPolicy AllowCreate="false" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" /></samlp:AuthnRequest>""" self.assertSAMLRequestsEquals( decode_base64_and_inflate(saml_request).decode('utf-8'), expected_request) # if we set a next arg in the login view, it is preserverd # in the RelayState argument next = '/another-view/' response = self.client.get(reverse('saml2_login'), {'next': next}) self.assertEquals(response.status_code, 302) location = response['Location'] url = urlparse(location) self.assertEquals(url.hostname, 'idp.example.com') self.assertEquals(url.path, '/simplesaml/saml2/idp/SSOService.php') params = parse_qs(url.query) self.assert_('SAMLRequest' in params) self.assert_('RelayState' in params) self.assertEquals(params['RelayState'][0], next)
def assertUrisEqual(testcase, expected, actual): """Test that URIs are the same, up to reordering of query parameters.""" expected = urlparse(expected) actual = urlparse(actual) testcase.assertEqual(expected.scheme, actual.scheme) testcase.assertEqual(expected.netloc, actual.netloc) testcase.assertEqual(expected.path, actual.path) testcase.assertEqual(expected.params, actual.params) testcase.assertEqual(expected.fragment, actual.fragment) expected_query = parse_qs(expected.query) actual_query = parse_qs(actual.query) for name in list(expected_query.keys()): testcase.assertEqual(expected_query[name], actual_query[name]) for name in list(actual_query.keys()): testcase.assertEqual(expected_query[name], actual_query[name])
def _http_get(service, url, *args, **kwargs): url_parts = urlparse(url) path = url_parts.path query = parse_qs(url_parts.query) if path == '/api/2.0/repositories/myuser/myrepo/': self.assertEqual( query, { 'fields': ['mainbranch.name'], }) return get_repository_api_response, None elif path == '/api/2.0/repositories/myuser/myrepo/refs/branches': if 'page' in query: self.assertEqual( query, { 'fields': ['values.name,values.target.hash,next'], 'pagelen': ['100'], 'page': ['2'], }) return branches_api_response_2, None else: self.assertEqual( query, { 'fields': ['values.name,values.target.hash,next'], 'pagelen': ['100'], }) return branches_api_response_1, None else: self.fail('Unexpected URL %s' % url)
def process_authn_request_redirect(self, url, auth_result=True, consent=True): login = lasso.Login(self.server) login.processAuthnRequestMsg(url.split('?', 1)[1]) # See # https://docs.python.org/2/library/zlib.html#zlib.decompress # for the -15 magic value. # # * -8 to -15: Uses the absolute value of wbits as the window size # logarithm. The input must be a raw stream with no header or trailer. # # it means Deflate instead of GZIP (same stream no header, no trailer) self.request = zlib.decompress( base64.b64decode( urlparse.parse_qs( urlparse.urlparse(url).query)['SAMLRequest'][0]), -15) try: login.validateRequestMsg(auth_result, consent) except lasso.LoginRequestDeniedError: pass else: login.buildAssertion(lasso.SAML_AUTHENTICATION_METHOD_PASSWORD, "FIXME", "FIXME", "FIXME", "FIXME") if login.protocolProfile == lasso.LOGIN_PROTOCOL_PROFILE_BRWS_ART: login.buildArtifactMsg(lasso.HTTP_METHOD_ARTIFACT_GET) self.artifact = login.artifact self.artifact_message = login.artifactMessage elif login.protocolProfile == lasso.LOGIN_PROTOCOL_PROFILE_BRWS_POST: login.buildAuthnResponseMsg() else: raise NotImplementedError return login.msgUrl, login.msgBody, login.msgRelayState
def test_logout(self): settings.SAML_CONFIG = conf.create_conf( sp_host='sp.example.com', idp_hosts=['idp.example.com'], metadata_file='remote_metadata_one_idp.xml', ) self.do_login() response = self.client.get(reverse('saml2_logout')) self.assertEqual(response.status_code, 302) location = response['Location'] url = urlparse(location) self.assertEqual(url.hostname, 'idp.example.com') self.assertEqual(url.path, '/simplesaml/saml2/idp/SingleLogoutService.php') params = parse_qs(url.query) self.assertIn('SAMLRequest', params) saml_request = params['SAMLRequest'][0] if PY_VERSION < (3,): expected_request = """<?xml version='1.0' encoding='UTF-8'?> <samlp:LogoutRequest xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Destination="https://idp.example.com/simplesaml/saml2/idp/SingleLogoutService.php" ID="XXXXXXXXXXXXXXXXXXXXXX" IssueInstant="2010-01-01T00:00:00Z" Reason="" Version="2.0"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://sp.example.com/saml2/metadata/</saml:Issuer><saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" SPNameQualifier="http://sp.example.com/saml2/metadata/">58bcc81ea14700f66aeb707a0eff1360</saml:NameID><samlp:SessionIndex>a0123456789abcdef0123456789abcdef</samlp:SessionIndex></samlp:LogoutRequest>""" else: expected_request = """<samlp:LogoutRequest xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Destination="https://idp.example.com/simplesaml/saml2/idp/SingleLogoutService.php" ID="XXXXXXXXXXXXXXXXXXXXXX" IssueInstant="2010-01-01T00:00:00Z" Reason="" Version="2.0"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://sp.example.com/saml2/metadata/</saml:Issuer><saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" SPNameQualifier="http://sp.example.com/saml2/metadata/">58bcc81ea14700f66aeb707a0eff1360</saml:NameID><samlp:SessionIndex>a0123456789abcdef0123456789abcdef</samlp:SessionIndex></samlp:LogoutRequest>""" self.assertSAMLRequestsEquals(decode_base64_and_inflate(saml_request).decode('utf-8'), expected_request)
def test_login_several_idps(self): settings.SAML_CONFIG = conf.create_conf( sp_host='sp.example.com', idp_hosts=['idp1.example.com', 'idp2.example.com', 'idp3.example.com'], metadata_file='remote_metadata_three_idps.xml', ) response = self.client.get(reverse('saml2_login')) # a WAYF page should be displayed self.assertContains(response, 'Where are you from?', status_code=200) for i in range(1, 4): link = '/login/?idp=https://idp%d.example.com/simplesaml/saml2/idp/metadata.php&next=/' self.assertContains(response, link % i) # click on the second idp response = self.client.get(reverse('saml2_login'), { 'idp': 'https://idp2.example.com/simplesaml/saml2/idp/metadata.php', 'next': '/', }) self.assertEqual(response.status_code, 302) location = response['Location'] url = urlparse(location) self.assertEqual(url.hostname, 'idp2.example.com') self.assertEqual(url.path, '/simplesaml/saml2/idp/SSOService.php') params = parse_qs(url.query) self.assertIn('SAMLRequest', params) self.assertIn('RelayState', params) saml_request = params['SAMLRequest'][0] if 'AuthnRequest xmlns' not in decode_base64_and_inflate(saml_request).decode('utf-8'): raise Exception('Not a valid AuthnRequest')
def post(url, params): """ Make a POST request to the URL using the key-value pairs. Return a set of key-value pairs. :url: URL to post to :params: Dict of parameters to include in post payload """ payload = urlencode(params) start_time = time.time() response = requests.post( url, payload, headers={'content-type': 'text/namevalue; charset=utf-8'}) if response.status_code != requests.codes.ok: raise exceptions.PayPalError("Unable to communicate with PayPal") # Convert response into a simple key-value format pairs = {} for key, values in parse_qs(response.text).items(): pairs[force_text(key)] = force_text(values[0]) #pairs[key] = values[0] # Add audit information pairs['_raw_request'] = payload pairs['_raw_response'] = response.content pairs['_response_time'] = (time.time() - start_time) * 1000.0 return pairs
def _add_query_params(self, url, new_query_params): """Add query parameters onto the given URL. Args: url (unicode): The URL to add query parameters to. new_query_params (dict): The query parameters to add. Returns: unicode: The resulting URL. """ scheme, netloc, path, query_string, fragment = urlsplit(url) query_params = parse_qs(query_string) query_params.update(new_query_params) new_query_string = urlencode( [ (key, value) for key, value in sorted(six.iteritems(query_params), key=lambda i: i[0]) ], doseq=True) return urlunsplit((scheme, netloc, path, new_query_string, fragment))
def _decode_cursor(encoded): """ Given a string representing an encoded cursor, return a `Cursor` instance. """ # The offset in the cursor is used in situations where we have a # nearly-unique index. (Eg millisecond precision creation timestamps) # We guard against malicious users attempting to cause expensive database # queries, by having a hard cap on the maximum possible size of the offset. OFFSET_CUTOFF = 1000 try: querystring = b64decode(encoded.encode('ascii')).decode('ascii') tokens = urlparse.parse_qs(querystring, keep_blank_values=True) offset = tokens.get('o', ['0'])[0] offset = _positive_int(offset, cutoff=OFFSET_CUTOFF) reverse = tokens.get('r', ['0'])[0] reverse = bool(int(reverse)) position = tokens.get('p', [None])[0] except (TypeError, ValueError): return None return Cursor(offset=offset, reverse=reverse, position=position)
def url_replace_param(url, name, value): """ Replace a GET parameter in an URL """ url_components = urlparse(force_str(url)) params = parse_qs(url_components.query) if value is None: del params[name] else: params[name] = value return mark_safe( urlunparse( [ url_components.scheme, url_components.netloc, url_components.path, url_components.params, urlencode(params, doseq=True), url_components.fragment, ] ) )
def build_html_iframe(response, url_params=None, iframe_attrs=None): html = response.get('html', '') if url_params is None: url_params = {} if iframe_attrs is None: iframe_attrs = {} if html: # What follows is a pretty nasty looking "hack" # oEmbed hss not implemented some parameters # and so for these we need to add them manually to the iframe. html = BeautifulSoup(html).iframe data_url = response.get('player_url', html['src']) player_url = urlparse(data_url) queries = parse_qs(player_url.query) url_params.update(queries) url_parts = list(player_url) url_parts[4] = urlencode(url_params, True) html['src'] = urlunparse(url_parts) for key, value in iframe_attrs.items(): if value: html[key] = value return str(html)
def decode_cursor(self, request): """ Given a request with a cursor, return a `Cursor` instance. Differs from the standard CursorPagination to handle a tuple in the position field. """ # Determine if we have a cursor, and if so then decode it. encoded = request.query_params.get(self.cursor_query_param) if encoded is None: return None try: querystring = b64decode(encoded.encode('ascii')).decode('ascii') tokens = urlparse.parse_qs(querystring, keep_blank_values=True) offset = tokens.get('o', ['0'])[0] # This was hard-coded until Django REST Framework 3.4.0. try: offset_cutoff = self.offset_cutoff except AttributeError: offset_cutoff = 1000 offset = _positive_int(offset, cutoff=offset_cutoff) reverse = tokens.get('r', ['0'])[0] reverse = bool(int(reverse)) # The difference. Don't get just the 0th entry: get all entries. position = tokens.get('p', None) except (TypeError, ValueError): raise NotFound(self.invalid_cursor_message) return Cursor(offset=offset, reverse=reverse, position=position)
def build_html_iframe(response, url_params=None, iframe_attrs=None): html = response.get('html', '') if url_params is None: url_params = {} if iframe_attrs is None: iframe_attrs = {} if html: # What follows is a pretty nasty looking "hack" # oEmbed hss not implemented some parameters # and so for these we need to add them manually to the iframe. html = BeautifulSoup(html).iframe data_url = response.get('player_url', html['src']) player_url = urlparse(data_url) queries = parse_qs(player_url.query) url_params.update(queries) url_parts = list(player_url) url_parts[4] = urlencode(url_params, True) html['src'] = urlunparse(url_parts) for key, value in iframe_attrs.iteritems(): if value: html[key] = value return unicode(html)
def decode_cursor(self, request): """ Given a request with a cursor, return a `Cursor` instance. """ # Determine if we have a cursor, and if so then decode it. encoded = request.query_params.get(self.cursor_query_param) if encoded is None: return None # The offset in the cursor is used in situations where we have a # nearly-unique index. (Eg millisecond precision creation timestamps) # We guard against malicious users attempting to cause expensive database # queries, by having a hard cap on the maximum possible size of the offset. OFFSET_CUTOFF = 1000 try: querystring = b64decode(encoded.encode('ascii')).decode('ascii') tokens = urlparse.parse_qs(querystring, keep_blank_values=True) offset = tokens.get('o', ['0'])[0] offset = _positive_int(offset, cutoff=OFFSET_CUTOFF) reverse = tokens.get('r', ['0'])[0] reverse = bool(int(reverse)) position = tokens.get('p', [None])[0] except (TypeError, ValueError): raise NotFound(self.invalid_cursor_message) return Cursor(offset=offset, reverse=reverse, position=position)
def test_json_build_query(self): model = JsonModel(data_wrapper=False) headers = {} path_params = {} query_params = {'foo': 1, 'bar': u'\N{COMET}', 'baz': ['fe', 'fi', 'fo', 'fum'], # Repeated parameters 'qux': []} body = {} headers, unused_params, query, body = model.request( headers, path_params, query_params, body) self.assertEqual(headers['accept'], 'application/json') self.assertEqual(headers['content-type'], 'application/json') query_dict = parse_qs(query[1:]) self.assertEqual(query_dict['foo'], ['1']) if six.PY3: # Python 3, no need to encode self.assertEqual(query_dict['bar'], [u'\N{COMET}']) else: # Python 2, encode string self.assertEqual(query_dict['bar'], [u'\N{COMET}'.encode('utf-8')]) self.assertEqual(query_dict['baz'], ['fe', 'fi', 'fo', 'fum']) self.assertTrue('qux' not in query_dict) self.assertEqual(body, '{}')
def test_logout_service_global(self): settings.SAML_CONFIG = conf.create_conf( sp_host='sp.example.com', idp_hosts=['idp.example.com'], metadata_file='remote_metadata_one_idp.xml', ) self.do_login() # now simulate a global logout process initiated by another SP subject_id = views._get_subject_id(self.client.session) instant = datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ') saml_request = """<?xml version='1.0' encoding='UTF-8'?> <samlp:LogoutRequest xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="_9961abbaae6d06d251226cb25e38bf8f468036e57e" Version="2.0" IssueInstant="%s" Destination="http://sp.example.com/saml2/ls/"><saml:Issuer>https://idp.example.com/simplesaml/saml2/idp/metadata.php</saml:Issuer><saml:NameID SPNameQualifier="http://sp.example.com/saml2/metadata/" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">%s</saml:NameID><samlp:SessionIndex>_1837687b7bc9faad85839dbeb319627889f3021757</samlp:SessionIndex></samlp:LogoutRequest>""" % ( instant, subject_id.text) response = self.client.get( reverse('saml2_ls'), { 'SAMLRequest': deflate_and_base64_encode(saml_request), }) self.assertEqual(response.status_code, 302) location = response['Location'] url = urlparse(location) self.assertEqual(url.hostname, 'idp.example.com') self.assertEqual(url.path, '/simplesaml/saml2/idp/SingleLogoutService.php') params = parse_qs(url.query) self.assertIn('SAMLResponse', params) saml_response = params['SAMLResponse'][0] if 'Response xmlns' not in decode_base64_and_inflate( saml_response).decode('utf-8'): raise Exception('Not a valid Response')
def test_logout(self): settings.SAML_CONFIG = conf.create_conf( sp_host='sp.example.com', idp_hosts=['idp.example.com'], metadata_file='remote_metadata_one_idp.xml', ) self.do_login() response = self.client.get(reverse('saml2_logout')) self.assertEqual(response.status_code, 302) location = response['Location'] url = urlparse(location) self.assertEqual(url.hostname, 'idp.example.com') self.assertEqual(url.path, '/simplesaml/saml2/idp/SingleLogoutService.php') params = parse_qs(url.query) self.assertIn('SAMLRequest', params) saml_request = params['SAMLRequest'][0] if PY_VERSION < (3, ): expected_request = """<?xml version='1.0' encoding='UTF-8'?> <samlp:LogoutRequest xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Destination="https://idp.example.com/simplesaml/saml2/idp/SingleLogoutService.php" ID="XXXXXXXXXXXXXXXXXXXXXX" IssueInstant="2010-01-01T00:00:00Z" Reason="" Version="2.0"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://sp.example.com/saml2/metadata/</saml:Issuer><saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" SPNameQualifier="http://sp.example.com/saml2/metadata/">58bcc81ea14700f66aeb707a0eff1360</saml:NameID><samlp:SessionIndex>a0123456789abcdef0123456789abcdef</samlp:SessionIndex></samlp:LogoutRequest>""" else: expected_request = """<samlp:LogoutRequest xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Destination="https://idp.example.com/simplesaml/saml2/idp/SingleLogoutService.php" ID="XXXXXXXXXXXXXXXXXXXXXX" IssueInstant="2010-01-01T00:00:00Z" Reason="" Version="2.0"><saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://sp.example.com/saml2/metadata/</saml:Issuer><saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" SPNameQualifier="http://sp.example.com/saml2/metadata/">58bcc81ea14700f66aeb707a0eff1360</saml:NameID><samlp:SessionIndex>a0123456789abcdef0123456789abcdef</samlp:SessionIndex></samlp:LogoutRequest>""" self.assertSAMLRequestsEquals( decode_base64_and_inflate(saml_request).decode('utf-8'), expected_request)
def post(url, params): """ Make a POST request to the URL using the key-value pairs. Return a set of key-value pairs. :url: URL to post to :params: Dict of parameters to include in post payload """ payload = urlencode(params) start_time = time.time() response = requests.post( url, payload, headers={'content-type': 'text/namevalue; charset=utf-8'}) if response.status_code != requests.codes.ok: raise exceptions.PayPalError("Unable to communicate with PayPal") # Convert response into a simple key-value format pairs = {} for key, values in parse_qs(response.content).items(): pairs[force_text(key)] = force_text(values[0]) # Add audit information pairs['_raw_request'] = payload pairs['_raw_response'] = response.content pairs['_response_time'] = (time.time() - start_time) * 1000.0 return pairs
def get_redirect_url(self, *args, **kwargs): parse_result = urlparse( self.request.META.get('HTTP_REFERER', resolve_url(settings.LOGIN_REDIRECT_URL))) query_dict = parse_qs(parse_result.query) resolver_match = resolve(parse_result.path) # Default is to stay on the same view url = parse_result.path new_object = self.navigation_function() # Inject new_object pk in the referer's view pk or object_id kwargs if 'pk' in resolver_match.kwargs: resolver_match.kwargs['pk'] = new_object.pk url = reverse(resolver_match.view_name, kwargs=resolver_match.kwargs) elif 'object_id' in resolver_match.kwargs: resolver_match.kwargs['object_id'] = new_object.pk url = reverse(resolver_match.view_name, kwargs=resolver_match.kwargs) else: messages.warning( self.request, _('Unknown view keyword argument schema, unable to ' 'redirect.')) return '{}?{}'.format(url, urlencode(query_dict, doseq=True))
def test_logout(self): settings.SAML_CONFIG = conf.create_conf( sp_host='sp.example.com', idp_hosts=['idp.example.com'], metadata_file='remote_metadata_one_idp.xml', ) self.do_login() response = self.client.get(reverse('saml2_logout')) self.assertEqual(response.status_code, 302) location = response['Location'] url = urlparse(location) self.assertEqual(url.hostname, 'idp.example.com') self.assertEqual(url.path, '/simplesaml/saml2/idp/SingleLogoutService.php') params = parse_qs(url.query) self.assertIn('SAMLRequest', params) saml_request = params['SAMLRequest'][0] if 'LogoutRequest xmlns' not in decode_base64_and_inflate( saml_request).decode('utf-8'): raise Exception('Not a valid LogoutRequest')
def test_nested_resources(self): self.http = HttpMock(datafile('zoo.json'), {'status': '200'}) zoo = build('zoo', 'v1', http=self.http) self.assertTrue(getattr(zoo, 'animals')) request = zoo.my().favorites().list(max_results="5") parsed = urlparse(request.uri) q = parse_qs(parsed[4]) self.assertEqual(q['max-results'], ['5'])
def test_string_params_value_of_none_get_dropped(self): http = HttpMock(datafile('zoo.json'), {'status': '200'}) zoo = build('zoo', 'v1', http=http) request = zoo.query(trace=None, fields='description') parsed = urlparse(request.uri) q = parse_qs(parsed[4]) self.assertFalse('trace' in q)
def test_top_level_functions(self): self.http = HttpMock(datafile('zoo.json'), {'status': '200'}) zoo = build('zoo', 'v1', http=self.http) self.assertTrue(getattr(zoo, 'query')) request = zoo.query(q="foo") parsed = urlparse(request.uri) q = parse_qs(parsed[4]) self.assertEqual(q['q'], ['foo'])
def test_only_without(self): context = Context({"request": build_request("/?a=b&name=dog&c=5"), "a_var": "a"}) template = Template( "{% load django_tables2 %}" '<b>{% querystring without "a" "name" %}</b>' ) url = parse(template.render(context)).text qs = parse_qs(url[1:]) # trim the ? self.assertEqual(set(qs.keys()), set(["c"]))
def get_title_from_url(url): """Get title from url""" if not url: return parsed_url = urlparse(url) query = parse_qs(parsed_url.query) if 'title' in query: return query['title'][0]
def test_optional_stack_query_parameters(self): http = HttpMock(datafile('zoo.json'), {'status': '200'}) zoo = build('zoo', 'v1', http=http) request = zoo.query(trace='html', fields='description') parsed = urlparse(request.uri) q = parse_qs(parsed[4]) self.assertEqual(q['trace'], ['html']) self.assertEqual(q['fields'], ['description'])
def test_model_added_query_parameters(self): http = HttpMock(datafile('zoo.json'), {'status': '200'}) zoo = build('zoo', 'v1', http=http) request = zoo.animals().get(name='Lion') parsed = urlparse(request.uri) q = parse_qs(parsed[4]) self.assertEqual(q['alt'], ['json']) self.assertEqual(request.headers['accept'], 'application/json')
def test_fallback_to_raw_model(self): http = HttpMock(datafile('zoo.json'), {'status': '200'}) zoo = build('zoo', 'v1', http=http) request = zoo.animals().getmedia(name='Lion') parsed = urlparse(request.uri) q = parse_qs(parsed[4]) self.assertTrue('alt' not in q) self.assertEqual(request.headers['accept'], '*/*')
def test_next_successful_with_next_page_token(self): self.http = HttpMock(datafile('tasks.json'), {'status': '200'}) tasks = build('tasks', 'v1', http=self.http) request = tasks.tasklists().list() next_request = tasks.tasklists().list_next( request, {'nextPageToken': '123abc'}) parsed = list(urlparse(next_request.uri)) q = parse_qs(parsed[4]) self.assertEqual(q['pageToken'][0], '123abc')
def test_querystring_templatetag_supports_without(): context = Context({ 'request': build_request('/?a=b&name=dog&c=5'), 'a_var': 'a', }) template = Template('{% load django_tables2 %}' '<b>{% querystring "name"="Brad" without a_var %}</b>') url = parse(template.render(context)).text qs = parse_qs(url[1:]) # trim the ? assert set(qs.keys()) == set(['name', 'c']) # Try with only exclusions template = Template('{% load django_tables2 %}' '<b>{% querystring without "a" "name" %}</b>') url = parse(template.render(context)).text qs = parse_qs(url[1:]) # trim the ? assert set(qs.keys()) == set(["c"])
def test_querystring_templatetag_supports_without(): context = Context({ "request": build_request('/?a=b&name=dog&c=5'), "a_var": "a", }) template = Template('{% load django_tables2 %}' '<b>{% querystring "name"="Brad" without a_var %}</b>') url = parse(template.render(context)).text qs = parse_qs(url[1:]) # trim the ? assert set(qs.keys()) == set(["name", "c"]) # Try with only exclusions template = Template('{% load django_tables2 %}' '<b>{% querystring without "a" "name" %}</b>') url = parse(template.render(context)).text qs = parse_qs(url[1:]) # trim the ? assert set(qs.keys()) == set(["c"])
def _check_query_types(self, request): parsed = urlparse(request.uri) q = parse_qs(parsed[4]) self.assertEqual(q['q'], ['foo']) self.assertEqual(q['i'], ['1']) self.assertEqual(q['n'], ['1.0']) self.assertEqual(q['b'], ['false']) self.assertEqual(q['a'], ['[1, 2, 3]']) self.assertEqual(q['o'], ['{\'a\': 1}']) self.assertEqual(q['e'], ['bar'])
def test_only_without(self): context = Context({ 'request': build_request('/?a=b&name=dog&c=5'), 'a_var': 'a', }) template = Template('{% load django_tables2 %}' '<b>{% querystring without "a" "name" %}</b>') url = parse(template.render(context)).text qs = parse_qs(url[1:]) # trim the ? self.assertEqual(set(qs.keys()), set(["c"]))
def test_construct_with_per_page(self): """Testing APIPaginator construction with per_page=<value>""" url = 'http://example.com/api/list/?foo=1' paginator = DummyAPIPaginator(None, url, per_page=10) parts = urlsplit(paginator.url) query_params = parse_qs(parts[3]) self.assertEqual(query_params['foo'], ['1']) self.assertEqual(query_params['per-page'], ['10'])
def _add_query_params(self, url, new_query_params): """Adds query parameters onto the given URL.""" scheme, netloc, path, query_string, fragment = urlsplit(url) query_params = parse_qs(query_string) query_params.update(new_query_params) new_query_string = urlencode([(key, value) for key, value in sorted( six.iteritems(query_params), key=lambda i: i[0])], doseq=True) return urlunsplit((scheme, netloc, path, new_query_string, fragment))
def test_sp_initiated_login_discovery_service(private_settings, client): private_settings.MELLON_DISCOVERY_SERVICE_URL = 'https://disco' response = client.get('/login/') assert response.status_code == 302 params = parse_qs(urlparse(response['Location']).query) assert response['Location'].startswith('https://disco?') assert params == { 'return': ['http://testserver/login/?nodisco=1'], 'entityID': ['http://testserver/metadata/'] }
def remove_query_param(url, key): """ Given a URL and a key/val pair, remove an item in the query parameters of the URL, and return the new URL. """ (scheme, netloc, path, query, fragment) = urlparse.urlsplit(url) query_dict = urlparse.parse_qs(query) query_dict.pop(key, None) query = urlparse.urlencode(sorted(list(query_dict.items())), doseq=True) return urlparse.urlunsplit((scheme, netloc, path, query, fragment))
def replace_query_param(url, key, val): """ Given a URL and a key/val pair, set or replace an item in the query parameters of the URL, and return the new URL. """ (scheme, netloc, path, query, fragment) = urlparse.urlsplit(url) query_dict = urlparse.parse_qs(query, keep_blank_values=True) query_dict[key] = [val] query = urlparse.urlencode(sorted(list(query_dict.items())), doseq=True) return urlparse.urlunsplit((scheme, netloc, path, query, fragment))
def test_full_featured(self): # Zoo should exercise all discovery facets # and should also have no future.json file. self.http = HttpMock(datafile('zoo.json'), {'status': '200'}) zoo = build('zoo', 'v1', http=self.http) self.assertTrue(getattr(zoo, 'animals')) request = zoo.animals().list(name='bat', projection="full") parsed = urlparse(request.uri) q = parse_qs(parsed[4]) self.assertEqual(q['name'], ['bat']) self.assertEqual(q['projection'], ['full'])
def test_config_url(self): with override_settings(OTP_TOTP_ISSUER=None): url = self.device.config_url parsed = urlsplit(url) params = parse_qs(parsed.query) self.assertEqual(parsed.scheme, 'otpauth') self.assertEqual(parsed.netloc, 'totp') self.assertEqual(parsed.path, '/alice') self.assertIn('secret', params) self.assertNotIn('issuer', params)
def test_config_url_issuer(self): with override_settings(OTP_HOTP_ISSUER='example.com'): url = self.device.config_url parsed = urlsplit(url) params = parse_qs(parsed.query) self.assertEqual(parsed.scheme, 'otpauth') self.assertEqual(parsed.netloc, 'hotp') self.assertEqual(parsed.path, '/example.com%3Aalice') self.assertIn('secret', params) self.assertIn('issuer', params)
def test_login_one_idp(self): # monkey patch SAML configuration settings.SAML_CONFIG = conf.create_conf( sp_host='sp.example.com', idp_hosts=['idp.example.com'], metadata_file='remote_metadata_one_idp.xml', ) response = self.client.get(reverse('saml2_login')) self.assertEqual(response.status_code, 302) location = response['Location'] url = urlparse(location) self.assertEqual(url.hostname, 'idp.example.com') self.assertEqual(url.path, '/simplesaml/saml2/idp/SSOService.php') params = parse_qs(url.query) self.assertIn('SAMLRequest', params) self.assertIn('RelayState', params) saml_request = params['SAMLRequest'][0] if 'AuthnRequest xmlns' not in decode_base64_and_inflate( saml_request).decode('utf-8'): raise Exception('Not a valid AuthnRequest') # if we set a next arg in the login view, it is preserverd # in the RelayState argument next = '/another-view/' response = self.client.get(reverse('saml2_login'), {'next': next}) self.assertEqual(response.status_code, 302) location = response['Location'] url = urlparse(location) self.assertEqual(url.hostname, 'idp.example.com') self.assertEqual(url.path, '/simplesaml/saml2/idp/SSOService.php') params = parse_qs(url.query) self.assertIn('SAMLRequest', params) self.assertIn('RelayState', params) self.assertEqual(params['RelayState'][0], next)
def test_config_url_issuer_spaces(self): with override_settings(OTP_TOTP_ISSUER='Very Trustworthy Source'): url = self.device.config_url parsed = urlsplit(url) params = parse_qs(parsed.query) self.assertEqual(parsed.scheme, 'otpauth') self.assertEqual(parsed.netloc, 'totp') self.assertEqual(parsed.path, '/Very%20Trustworthy%20Source%3Aalice') self.assertIn('secret', params) self.assertIn('issuer', params) self.assertEqual(params['issuer'][0], 'Very Trustworthy Source')
def test_email_alert_sent(self): root = self.create_thread_for_user(self.sender, self.recipient) from django.core.mail import outbox self.assertEqual(len(outbox), 1) self.assertEqual(len(outbox[0].recipients()), 1) self.assertEqual(outbox[0].recipients()[0], self.recipient.email) html_message = get_html_message(outbox[0]) self.assertTrue(root.text in html_message) soup = BeautifulSoup(html_message) links = soup.find_all('a', attrs={'class': 'thread-link'}) self.assertEqual(len(links), 1) parse_result = urlparse(links[0]['href']) query = parse_qs(parse_result.query.replace('&', '&')) self.assertEqual(query['thread_id'][0], str(root.id))
def _add_query_params(self, url, new_query_params): """Adds query parameters onto the given URL.""" scheme, netloc, path, query_string, fragment = urlsplit(url) query_params = parse_qs(query_string) query_params.update(new_query_params) new_query_string = urlencode( [ (key, value) for key, value in sorted(six.iteritems(query_params), key=lambda i: i[0]) ], doseq=True) return urlunsplit((scheme, netloc, path, new_query_string, fragment))
def replace_query_param(url, key, val): """ Given a URL and a key/val pair, set or replace an item in the query parameters of the URL, and return the new URL. Forked from rest_framework.utils.urls; overwriten here because we need to pass keep_blank_values=True to urlparse.parse_qs() so that it doesn't remove the ?filter[id__in]= blank query parameter from our links in the case of an empty remote to-many link. """ (scheme, netloc, path, query, fragment) = urlparse.urlsplit(url) query_dict = urlparse.parse_qs(query, keep_blank_values=True) query_dict[key] = [val] query = urlparse.urlencode(sorted(list(query_dict.items())), doseq=True) return urlparse.urlunsplit((scheme, netloc, path, query, fragment))