Django: capture authorization token from another service - python

I'm trying to capture an authentication token from another service authenticator. In summary, I have a form login that serve client with two options to sign in, throw the normal login, or a link to a second authenticator service which will redirect to a particular form page. Once the user is signed, this second authenticator service will redirect back to my application, with a token as param.
I would like to include a kind of listener in my application (small script), in a way that when this redirect happen, I could capture and validate the token, finally, authenticate the user in the local django application.

I just came out with a simple solution since I was searching for an automatic capturing of a request. So, considering that the external authentication server redirect to a preinformed URL right after to authenticate, this URL could be capture in my localhost application by editing /etc/hosts AND nginx.conf (as suggest here), not just one or another. So, the first:
127.0.0.1 url-redirect-by-external-server.com
and nginx.conf, I have added a new server properties to the file:
...
server {
listen 80;
listen 443;
server_name url-redirect-by-external-server.com;
location / {
proxy_pass http://127.0.0.1:8000/myapp/exact-name-of-the-method-in-view-to-handle-the-request/;
}
}
...
The point is, when the request is made by the external server, the app still does not capture. When I press Enter to the URL, then, everything runs fine. Still did not figure what should be set.

Related

React app can't reach to backend python application on localhost on same server

I have a public cloud VM which has public IP say 160.159.158.157 (this has a domain registered against it).
I have a Django application (backend) which is CORS-enabled and serves data through port 8080.
I have a React app running on the same VIM on a different port (3000), which is accessing the Django app and is supposed to produce a report.
The problem is that, when I use http://<domain-name>:8080/api/ or http://<public-ip>:8080/api/, my application is working fine,
but when I try to fetch data from localhost like http://localhost:8080/api/ or http://127.0.0.1:8080/api/, the React app fails to fetch data with the following error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://127.0.0.1:8080/api/. (Reason: CORS request did not succeed). Status code: (null).
Here's what I've tried:
axios.get(baseURL, { headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods':'GET,PUT,POST,DELETE,PATCH,OPTIONS',
}
but it didn't work. What should I do?
Looks like you've gotten confused where those headers need to be. You're setting them on the request to the backend, but they need to be set on the response from the backend. After all, it wouldn't be very good security if someone making a request could simply say "yeah, I'm ok, you should trust me".
The problem is going to be somewhere in your backend Django app, so double check the CORS config over there.

Using Flask-Login to Authenticate Nginx Reverse Proxy

I am implementing a modified version of Duo Labs' py_webauthn demo in order to add physical authentication to my website. The demo is built in Flask, and uses the flask-login library in conjunction with an SQLAlchemy database to store user data.
What I would ideally like is for the Flask app to act as an Nginx authenticator, such that a logged-in user is able to access other proxy_pass'ed services on the server.
I had originally attempted to implement the reverse proxies in Flask, but the only working solution I have found requires the Twisted framework (as services like Shellinabox require constant requests being made), which needs a entirely separate WSGI application to be set up—an unnecessary middleman that is difficult to integrate.
My ideal result would be for a user to initially access the server and be proxy-pass'ed to the Flask authentication server, then would be able to access several other reverse-proxied services through Nginx. I am still open to a Python reverse proxy, but have found that Nginx best suits my needs.
How should I go about integrating Flask and Nginx?
(The app.py file for the demo library is available here. The Webauthn functionality is simply built on top of flask-login.)
I solved it! It is possible to use the builtin Nginx auth_request with Flask as an authenticator. Simply, if Flask returns a 200 upon being queried by Nginx, Nginx will then allow another page to be accessed. Alternatively, an error 401 can be returned by the authenticator to send the user to the Nginx 401 page (which, in my case, then redirects them to the login page).
To replicate, add an authenticator in Flask:
#app.route("/auth")
def nginx_auth():
if current_user.is_authenticated:
return "You are logged in! Sweet!"
else:
return 'Sorry, but unfortunately you\'re not logged in.', 401
Then, in Nginx, point an auth_request to the authenticator, and redirect 401 to the login page.
location /ssh {
auth_request /auth;
proxy_pass http://localhost:4200/;
}
location = /auth {
internal;
proxy_pass https://localhost:8081/auth;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
error_page 401 = #error401;
location #error401 {
return 302 /login;
}
(Code modified from Nginx documentation.)
I had the same issue (authentication in my flask app results 404 when I redirect) and got here looking for an answer. My fix ended up being simpler.
In nginx.conf I set proxy_set_header Host $host; to proxy_set_header Host $http_host;. I am still figuring out why it worked. I'll update the answer if I do.

write a reverse proxy in node js to call the api in django

My frontend code is running in angular at node httpserver port 127.0.0.1:8081
My backend services runnning in python django framework at port 127.0.0.1:9000
While calling my backend servies from angular http methods throws cors exception
so i wrote a proxy controller in my node js
var http = require('http'),
httpProxy = require('http-proxy');
var proxy = httpProxy.createProxyServer();
http.createServer(function (req, res) {
// This simulates an operation that takes 500ms to execute
setTimeout(function () {
proxy.web(req, res, {
target: 'http://127.0.0.1:9000/dummy/'
});
}, 500);
}).listen(8080, "127.0.0.1");
to listen and bind at angular. i run as the node proxycontroller.js, results a another port no 127.0.0.1:8080
from proxy controller it calls my backend service and result json but from the angular js calling the proxy controller from the http.get() method results cors problem
please help to solve this problem.
Enable CORS in Django
Uses this third-party lib django-cors to do it.
You are getting CORS because you are making the call from your AngularJS app and its host is 127.0.0.1:8081, different from your Django app host 127.0.0.1:9000
The error said CORS is supported only for specific protocals like http:// etc. So you have to add http to that url. When you say, 127.0.0.1, the browser is unable to understand which protocol to use to access that url, should it be using http:// or data:// or chrome:// etc. So you've to explicitly say http://
You have to configure cors in the backend. The backend (the API server) much explcitly say a site is allowed using the http header I specified earlier. Otherwise, I can open your website, edit the frontend using chrome console and remove all the security stuff. It has the be in the backend.
as http://127.0.0.1:9000 from the front end angular app, dosent need to create proxy server to transfer the calls to backend service.

How to detect url callback request

I have a locally-run app that makes API calls to a website (tumblr.com). This involves setting some OAuth credentials; one step along the way requires extracting a key from a callback url that the server directs the browser to. So what I currently have the user do is:
Open an authorization link in a browser, which prompts them to authorize the OAuth application on the website
Click through the authorization page on the website (“Yes, I allow xxxxx app to access certain info associated with my account”)
Clicking Authorize app makes a request to the localhost which includes a parameter in the url. Meaning that tumblr will redirect the browser to the page http://localhost/?oauth_token={TOKEN}&oauth_verifier={VERIFIER}#_=_. I assume that causes a request to be made to the local machine when it does that.
The user is expected to isolate the key parameter in the url from the browser’s navigation bar, and paste it in the application.
So is there any way I can bypass steps 3 and 4 and simply have the app pick up the callback request instead of expecting the user to copy and paste it from the browser? I’m afraid I don’t know much about how to handle network requests in python.
To be clear, what I need to do is get the {VERIFIER} string.
okay first thing first, for http requests, a good python module is requests
http://docs.python-requests.org/en/master/
Then, your app gives a callback address to tumblr so that tumblr can tell to your app client info, or login error.
Now, your point 3 isn't clear.
"Clicking authorize app makes a request to localhost"
Actually clicking "authorize app" for the user makes a request to tumblr saying he accepts.
Then tumblr makes a request to your callback url passing the infos.
The callback url should probably be your server address, there you must have a script listening for tumblr, which will give you your special parameter to call their api...
In addition :
So when the users click "authorize app" there is a request to tumblr, which redirects the user to the callback url (adding oauth token and verifier).
Now, obviously, you can't ask for every user to have an http server running on their computer.
So you must set the callback url to your server.
So if you set it to "myserver.com/tumblr" for instance, the user will get redirected to your webpage, and you'll get on your server, and for that user session, the oauths token and verifier.
and...
Assuming your app is client only I'd say there are two options.
Either have your users enter manually their API keys.
Or either embed a webserver into your app.
In the case of the embedded webserver, I'd suggest flask for its simplicity.
Simply have your webserver listen on a given port and set the callback url to that server:port.
This way you'll get the client tokens directly.

Pylons - Redirects will drop from HTTPS to HTTP unless I specify the protocol... Is there a way to fix this?

On my Pylons website, I have my login form sending it's data to 'https://mysite.com'. Upon a successful login, a redirect takes place to send them to their profile page.
redirect(url(controller='profile'))
This sends the user to http://mysite.com/profile instead of https://mysite.com/profile. The only way I've found to fix this is to change the redirect to:
redirect(url(controller='profile', protocol='https'))
The problem I have with this is "what if, for whatever reason, my cert goes away and I have to drop SSL" I don't want to have to go through my entire code looking for all redirects I specify the 'https' protocol in. I want my login to send the user to HTTPS and that's it...
Is there a reason the redirect drops to HTTP? Is there a way to stop it? :/
Since I spent a couple of hours wading through the pylons/routes/beaker/etc. source I thought I'd share my solution.
First a bit of context. I'm using an elastic load balancer (ELB) on AWS with SSL termination. The application is built to run solely over https; this is a post-firesheep world after all. It's layered like so:
ELB -> nginx -> pasteWSGI -> pylons
ELB is jolly good in terms of simplicity but any call to pylons.controllers.util.redirect would trigger a 302 Redirect to "http://mysite/". The ELB would not change that on the way back (no reason to) and so my browser would be sent back to port 80 and there is no ELB listening on that port.
I've tried updating the Mapper as suggested above.
it did not work,
I wanted my redirects to be relative. Switching to https in pylons means that the URL generator goes and fetches the host to create a new URL (https://localhost/....)
Note that Mapper.redirect_to works out of the box and uses relative redirects so there is no need to mess with that. The fundamental problem is that controllers.redirect uses a slightly different code path. In particular, in Routes, the controllers.util.redirect is not a redirect (there's an "if routes and routes.redirect" which evals to False).
My solution: replace all calls to redirect by a new controller method (called redirect too) to change redirects from absolute to relative redirects.
The code is as follows:
lib/helpers.py
def relative_redirect(to_url, start_response):
"""Returns a redirect that is compatible with AWS ELB (no absolute http responses)
Using pylons.controllers.util.redirect triggers an exception that'll be turned into a 302
But with an absolute path so the response does not contains https but simple http
"""
start_response("302 Found", [("Content-Type", "text/plain; charset=utf-8"), ("Location", url(to_url))])
return ["You are being redirected to {0}".format(url(to_url))]
With that bit called from the base class of my controllers:
class BaseController(WSGIController):
...
def redirect(self, to_url):
"""Force a relative redirection, to work with AWS ELB"""
return relative_redirect(to_url, self.start_response)
I'd customize the Mapper so that every call to "url" would force the correct protocol...
Inside routing.py:
class CustomMapper(Mapper):
def generate(self, *args, **kwargs):
kwargs["protocol"] = "https"
return Mapper.generate(self, *args, **kwargs)
def make_map(config):
"""Create, configure and return the routes Mapper"""
map = CustomMapper(directory=config['pylons.paths']['controllers'],
always_scan=config['debug'])

Categories

Resources