So.. Back again with another flask question:
My application is set up largely around the use of subdomains for various portions instead of prefixes. As such, typical urls for my app look like this:
domain.tld/
domain.tld/about
admin.domain.tld/
admin.domain.tld/login
etc.
I'm composing unit tests and I've seem to run into a problem. I've done a lot of searching of the Flask and Werkzeug documentation but I can't seem to figure out how to fix my issue.
Basically, when I'm testing I'm trying to simulate a GET request to various urls.. and a lot of those URLs will fall on subdomains. I've tried the following which would seem to be logical:
with app.app_context():
url = url_for("admin.login") # returns http://admin.domain.tld:80/login
with app.test_client() as c:
resp = c.get(url) # Fails: returns 404
assert resp.data == "Expected test response", "Bad Response"
Now.. my c.get should return a response containing expected data at the url, but instead I'm being given the default 404 handler. This makes it quite hard to test many of my routes.
I've done some reading into Flask and found a github issue that notes that the test client expects a relative url... well.. I'm not sure how to provide that since I need to specify the subdomain.
Additionally, I've done further reading and discovered that the Flask test client is built on the Werkzeug test client and the Werkzeug test client contains an option for "allow_subdomain_redirects" that is normally false. Sadly, attempting to configure my Flask test client to have that behavior so far has failed (I might be doing it wrong).
Anyways, does anyone know how I can simulate a request in my flask app and target a subdomain? At the moment, I'm all out of ideas. Thanks for any suggestions. :)
So.. After a lot of debugging I have found the problem... and it seems to be a Flask issue after all, though not the one I linked above.
First, after LOTS of searching I found this archive here which seemed to give guidance on how to properly make the request for subdomains:
with app.test_client() as c:
c.get("/target/path.html", base_url="admin.domain.tld/")
There is a caveat, however... Depending on what app.config["SERVER_NAME"] is set to this might not work... Specifically, as of flask 0.11.1 if app.config["SERVER_NAME"] has an explicit port of 80 the above c.get will FAIL. (i.e. if SERVER_NAME looks like domain.tld:80 ) However.. if SERVER_NAME contains any other port it will function properly. (i.e. if SERVER_NAME looks like domain.tld:5000 everything will work fine)
I don't know if this is intended or not.. but it has caused me a lot of headache and work.. I'll be posting a github issue on it shortly just to make sure it is indeed intended.
Related
I was trying to do some simple authorization for ameritrade's developer platform. I was attempting.
According to the platform, the Endpoint I need to access is is:
https://auth.tdameritrade.com/auth?response_type=code&redirect_uri={uri}&client_id={client_id}}%40AMER.OAUTHAP
https://developer.tdameritrade.com/content/simple-auth-local-apps
When looking at the client_id, for the dev application, I was noticing that they may actually be referencing the Applications, Consumer Key instead? So i did just that, but when attempting to query the information, it returns: A third-party application may be attempting to make unauthorized access to your account. The reason why i think it is the consumer key, is listed at: https://developer.tdameritrade.com/content/getting-started
So I ended up doing something like:
from urllib.parse import urlencode, quote_plus
url = "https://auth.tdameritrade.com/auth?response_type=code&redirect_uri={uri}&client_id={client_id}}%40AMER.OAUTHAP".format(
uri=urlencode("http://localhost", quote_via=quote_plus),
client_id="JHBDFGJH45OOUDFHGJKSDBNG" #Sample
)
I dont think this is because I am currently in a different country currently, I think that something else is wrong here.
It doesnt follow through with it, but instead returns a 400 error with that information. Im not sure whats wrong though.
This happens when you copied the callback URI incorrectly. Imagine if this were a client application, and TD detected that the application is trying to send the user to a different URL than the app is configured with. If they send the callback request to that application, it will receive the token and gain full control over your account.
Have you double and triple checked that you're copying the callback URL correctly, protocol name, ports, and trailing slashes and everything? Also, consider using an API library instead of writing your own. You can find documentation about this specific error here.
I had this issue and I solved it using simply using http://127.0.0.1 on the call back URI of the App.
I then used below URL and it worked as expected.
https://auth.tdameritrade.com/auth?response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1&client_id={MyConsumerKey}%40AMER.OAUTHAP
Just in case anyone is still having this problem, make sure the callback URI is spelled EXACTLY the same as you specified when creating the app. I was having this problem because I set the callback on the TD developer website to "https://localhost/" and used "https://localhost" in the URL instead (missing the slash at the end). As soon as I added the slash at the end, it worked.
I found out that the issue is caused by the way the callback URL is set. It have to be exactly the same as the callback URL you have typed in at the apps details on the TD developer API page. I tried several permutations and indeed to get the authorization to work both have to be the same. eg. https or http.. end with '/' or does not, it matters. There is also no need to URL encode it.
We work on a product that is a series of components that could be installed on different CMSs and provide different services. We take a CMS agnostic approach and try to use the same code in all the CMSs as much as possible (we try to avoid using CMS API as much as we can).
Some part of the code needs to work with the current URL for some redirections so we use Request.Url.ToString() that is something that has worked fine in other environments but in Kentico instead of returning the current page we always get a reference to CMSPages/PortalTemplate.aspx with a querystring parameter aliasPath that holds the real URL. In addition to that, requesting the Template page using a browser gives you a 404 error.
Example:
Real URL (this works fine on a browser):
(1) https://www.customer.com/Membership/Questionnaire?Id=7207f9f9-7354-df11-88d9-005056837252
Request.Url.ToString() (this gives you a 404 error on a browser):
(2) https://www.customer.com/CMSPages/PortalTemplate.aspx?Id=7207f9f9-7354-df11-88d9-005056837252&aliaspath=/Membership/Questionnaire
I've noticed that the 404 error is thrown explicitly by the template code when invoked directly. Please see below code from Page_Init method of PortalTemplate.aspx.cs:
var resolvedTemplatePage = URLHelper.ResolveUrl(URLHelper.PortalTemplatePage);
if (RequestContext.RawURL.StartsWithCSafe(resolvedTemplatePage, true))
{
// Deny direct access to this page
RequestHelper.Respond404();
}
base.OnInit(e);
So, if I comment the above code out my redirection works fine ((2) resolves to (1)). I know it is not an elegant solution but since I cannot / don't want to use Kentico API is the only workaround I could find.
Note that I know that using Kentico API will solve the issue since I'm sure I will find an API method that will return the actual page. I'm trying to avoid that as much as possible.
Questions: Am I breaking something? Is there a better way of achieving what I trying to accomplish? Can you think on any good reason I shouldn't do what I'm doing (security, usability, etc)?
This is kind of a very broad question so I was not able to find any useful information on Kentico docs.
I'm testing all this on Kentico v8.2.50 which is the version one of my customers currently have.
Thanks in advance.
It's not really recommended to edit the source files of Kentico, as you may start to run into issues with future upgrades and also start to see some unexpected behaviour.
If you want to get the original URL sent to the server before Kentico's routing has done its work, you can use Page.Request.RawUrl. Using your above example, RawUrl would return a value of /Membership/Questionnaire?Id=7207f9f9-7354-df11-88d9-005056837252, whereas Url will return a Uri with a value of https://www.customer.com/CMSPages/PortalTemplate.aspx?Id=7207f9f9-7354-df11-88d9-005056837252&aliaspath=/Membership/Questionnaire (as you stated).
This should avoid needing to use the Kentico API and also avoid having to change a file that pretty much every request goes through when using the portal engine.
If you need to get the full URL to redirect to, you can use something like this:
var redirectUrl = Request.Url.GetLeftPart(UriPartial.Authority) + Request.RawUrl;
I have been spending some time learning how APIs work for a project I am working on.
I have been using the requests library to do so, and it has been very helpful. Right now I am working with the github api - https://api.github.com/
I ran into a problem when trying to make a call from this specific section of the API - Github-API-Call
The following is what I tried:
r = requests.get('https://api.github.com/users/{user}/repos{?type,page,per_page,sort}', auth = ('user', 'pass'))
When I make an attempt at checking the status code though with,
r.status_code
I get returned 404. I noticed that the URL looks strange, I was hoping that somebody might be able to let me know exactly what is going wrong, or explain why the URL looks strange in this example.
Really appreciate somebody taking the time out to explain it.
I am developing a single page application that has a client side router. so although the base url to run the application will be either http:://example.com or http:://example.com/index.html - skipping the domain name that is routes '/' and '/index.html'
But somewhere in my application, because of my client side router, I may call up a route something like '/appointments/20160113 and the client router will redirect me to the appropriate "Appointments Page" inside my SPA passing the parameter of todays date.
But if the user calls directly http://example.com/appointments/20160113, I am led to believe that the server should respond directly with /index.html so the browser doesn't get a 404.
I am building the server using nodejs (specifically the http2 module, but I don't think that is very important, and my examples don't use https, although with http2 they do). I just tried changing the server so if its hit with an unknown url it responds with the index.html file.
However, the browser sees this as its first response and then makes requests for the rest of its attached files relative to the url (so for instance follows up with /appointments/20160113/styles/main.css). This leads to an infinite loop, as the server responds with another copy in index.html (and immediately gets a request back for /appointments/20160113/styles/styles/main.css ).
Its too early in the lifecycle of the page for the javascript to be running yet (and specifically the router software), so clearly the approach is too simplistic.
I have also written the client side router (using the history api) so I can change things if I need to.
How should this situation be handled. I am thinking perhaps a 301 redirect to /index.html or something and then the router's initial dispatch knows this and can do a popstate or something. I ideally want to support the passing of urls via external means between users, but until I actually tried to implement it I hadn't realise the implications.
I don't know if this is the best way or not, but having not received any answers on here, I decided to try a number of different ways and see which worked out the best.
Each way involved doing a 301 redirect to /index.html, and then providing the url from which I was redirecting via different mechanisms
This is what I tried
Setting a cookie with a short expiry date the value of which was the url
Adding a query string with a ?redirect= parameter with the url
Adding a #fragment after /index.html with the url
In the end I rejected 1) because chrome wasn't deleting the cookie after I had used it and making the value shorted lived depends on accurate timing between client and server. The solution appeared too fragile.
I tried 2) and it was looking good until I came to test it. Unfortunately setting window.location.search causes a page reload, and I was really struggling with finding out what was happening. However, what I discovered in 3) about mocking could well be provided to a solution based on 2) so it is one that could be used. I still might return to this solution as it "feels" right to me.
I tried 3) and it worked quite well. However I was struggling with timing issues in testing since my router element was using the #fragment during initialisation, but I couldn't set the window.location.hash until after the router was established in the test suite. I wanted to mock window.location.hash with sinon so I could control it, but it turns out you can't
The solution to this was for the router to wrap its own calls to window.location.hash in a library, so that I could mock the library. And that is what I did in the end and it all worked.
I could go back to using a query string and wrapping window.location.search in a library call, so I could stub that call and avoid the problems of page reloading.
I have encountered a strange behaviour with express routes. I want to enter an ID via HTML-Form and fetch the result via ajav (jquery) to display the entry. All was working fine, till i have to expand the ID from numbers to strings (with slashes).
I edited all functions and calls. I check the strign with a reg ex and want to fetch the request with a modified route (express). but here comes the problem. i get it working under windows but it is failing on linux. Perhaps the problem is caused by the invrastructure, because the node.js app is located behind an reverse proxy apache2 to tunnel the service to public (with domain & cert).
what ever. perhaps somebody can help me set this thing up and get it running.
app.get(/^\/byId\/(.+)/, getSourceById);
not using req.params[0] in the called function. on the test server (windows) it is working even with the old route
app.get('/byId/:id', getSourceById);
because the html form does request %2F not /. How ever, both ways should work to fetch the request. But both aren't working for me. did i miss something?
i'm thankful for any help!
Found the answer of my question. It was indeed the reverse proxy who was blocking the request.
Simular problem: http://www.gossamer-threads.com/lists/apache/users/314562
How to solve the behaviour:
http://httpd.apache.org/docs/2.0/mod/core.html#allowencodedslashes
Default forbidden because of security issues. If you need it, use it carefully.