Web2py 3rd party authentication - python-2.7

I have made a webapp in python using web2py which has 3rd party authentication using Janrain as recommended.
On my local server it worked absolutely fine, but now when I deployed on pythonanywhere, the authentication is giving me the following error
"class 'urllib2.URLError' urlopen error Tunnel connection failed: 403 Forbidden"
Stack
===========
File "/usr/lib/python2.7/urllib2.py", line 127, in urlopen
return _opener.open(url, data, timeout)
File "/usr/lib/python2.7/urllib2.py", line 404, in open
response = self._open(req, data)
File "/usr/lib/python2.7/urllib2.py", line 422, in _open
'_open', req)
File "/usr/lib/python2.7/urllib2.py", line 382, in _call_chain
result = func(*args)
File "/usr/lib/python2.7/urllib2.py", line 1222, in https_open
return self.do_open(httplib.HTTPSConnection, req)
File "/usr/lib/python2.7/urllib2.py", line 1184, in do_open
raise URLError(err)
URLError: <urlopen error Tunnel connection failed: 403 Forbidden>
==========================
For third party authentication I had used yahoomail id.

This has now been fixed, but in case anyone else comes across this issue or a similar issue:
the problem was that free users on PythonAnywhere have restricted internet, that goes via a proxy and only allows a whitelist of sites.
The sites .janrain.com and .rpxnow.com weren't on the whitelist at the time, but we have now added them, and the janrain/yahoo mail login now works.
So, for anyone else that happens to be going via a proxy and trying to use this service, those are the sites you need to add. (may also be of interest to paranoid people that like to run noscript, if you find some federated auth system failing, you may need to unblock rpxnow).
Happy coding everyone!

Related

Posting Base64 with Axios cause [Errno 54] Connection reset by peer

I am currently working on a web-application using VueJS for the front-end and Django (Django Rest Framework) for the back-end.
One of the feature of the application is to send a pdf invoice by mail. So I was able to generate the pdf using "jspdf" library. And on Django side, I made an API end-point in order to send an email (with the pdf attached).
So the logic is (tell me if it's wrong to do that):
Converting the output pdf to Base64 on the front-end in order to post it to my "sendmail" endpoint with Axios.
Decoding the Base64 string on the back-end, write a temp pdf file, and attached it to send the mail.
It works perfectly, I tested it, the post request have a status 200. I receive the mail with the pdf attached... But on django side, I got "[Errno 54] Connection reset by peer".
Here's the full error:
[24/Nov/2020 21:50:53] "POST /api/sendmail/ HTTP/1.1" 200 0
--------------------------------------------
Exception happened during processing of request from ('127.0.0.1', 59267)
Traceback (most recent call last):
File "/Users/jjj/anaconda3/lib/python3.6/socketserver.py", line 639, in process_request_thread
self.finish_request(request, client_address)
File "/Users/jjj/anaconda3/lib/python3.6/socketserver.py", line 361, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "/Users/jjj/anaconda3/lib/python3.6/socketserver.py", line 696, in __init__
self.handle()
File "/Users/jjj/Documents/DEV/Environments/project1_env/lib/python3.6/site-packages/django/core/servers/basehttp.py", line 174, in handle
self.handle_one_request()
File "/Users/jjj/Documents/DEV/Environments/project1_env/lib/python3.6/site-packages/django/core/servers/basehttp.py", line 182, in handle_one_request
self.raw_requestline = self.rfile.readline(65537)
File "/Users/jjj/anaconda3/lib/python3.6/socket.py", line 586, in readinto
return self._sock.recv_into(b)
ConnectionResetError: [Errno 54] Connection reset by peer
The thing is that I tried to do a post request with Postman and it worked without any error... which drives me crazy.
So I suspect the error to be on the front side.
Here's my vue side code:
sendInvoice() {
var mailInfo = {
email: this.currentOrder.email,
pdf: printPDF(this.currentOrder, true)
}
this.postSendMail(mailInfo)
}
and here's my axios code:
postSendMail(context, mailInfo) {
return new Promise((resolve, reject) => {
getAPI.post('/sendmail/', mailInfo)
.then(() => {
resolve()
})
})
},
Do you have any ideas...? Thanks in advance.
Okay, I feel very dumb right now. I just spent 3 hours trying to understand the error.
The reason was that in my axios instance I set the timeout to 1000... and since my Base64 pdf string is quite heavy, it takes more than 1 second. I just set it to 5000 and it works perfectly now!

Zappa/AWS - Emails won't send and just timeout

Currently, I have tried both plain-old Django SMTP and a few different api-based Django libraries for my transactional email provider (Postmark).
When I run my development server, everything works perfectly. Emails send via the Postmark API with no problem.
When I deploy to AWS with Zappa, visit my website, and do a task that is supposed to send an email (Ex. Resetting a user's password) the page continually loads until it says Endpoint request timed out.
I have tried setting the timeout of my AWS Lambda function to a longer duration in case Django decides to throw an error.
Here is the error that was thrown. Just keep in mind this error only happens in production. I created a custom management command in able to retrieve this error.
HTTPSConnectionPool(host='api.postmarkapp.com', port=443): Max retries exceeded with url: /email/batch (Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7f6cfbd5dd30>: Failed to establish a new connection: [Errno 110] Connection timed out',)): ConnectionError
Traceback (most recent call last):
File "/var/task/handler.py", line 509, in lambda_handler
return LambdaHandler.lambda_handler(event, context)
File "/var/task/handler.py", line 240, in lambda_handler
return handler.handler(event, context)
File "/var/task/handler.py", line 376, in handler
management.call_command(*event['manage'].split(' '))
File "/var/task/django/core/management/__init__.py", line 131, in call_command
return command.execute(*args, **defaults)
File "/var/task/django/core/management/base.py", line 330, in execute
output = self.handle(*args, **options)
File "/var/task/users/management/commands/sendemail.py", line 13, in handle
fail_silently=False,
File "/var/task/django/core/mail/__init__.py", line 62, in send_mail
return mail.send()
File "/var/task/django/core/mail/message.py", line 348, in send
return self.get_connection(fail_silently).send_messages([self])
File "/var/task/postmarker/django/backend.py", line 66, in send_messages
responses = self.client.emails.send_batch(*prepared_messages, TrackOpens=self.get_option('TRACK_OPENS'))
File "/var/task/postmarker/models/emails.py", line 332, in send_batch
return self.EmailBatch(*emails).send(**extra)
File "/var/task/postmarker/models/emails.py", line 247, in send
responses = [self._manager._send_batch(*batch) for batch in chunks(emails, self.MAX_SIZE)]
File "/var/task/postmarker/models/emails.py", line 247, in <listcomp>
responses = [self._manager._send_batch(*batch) for batch in chunks(emails, self.MAX_SIZE)]
File "/var/task/postmarker/models/emails.py", line 276, in _send_batch
return self.call('POST', '/email/batch', data=emails)
File "/var/task/postmarker/models/base.py", line 72, in call
return self.client.call(*args, **kwargs)
File "/var/task/postmarker/core.py", line 106, in call
**kwargs
File "/var/task/postmarker/core.py", line 129, in _call
method, url, json=data, params=kwargs, headers=default_headers, timeout=self.timeout
File "/var/task/requests/sessions.py", line 508, in request
resp = self.send(prep, **send_kwargs)
File "/var/task/requests/sessions.py", line 618, in send
r = adapter.send(request, **kwargs)
File "/var/task/requests/adapters.py", line 508, in send
raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='api.postmarkapp.com', port=443): Max retries exceeded with url: /email/batch (Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7f6cfbd5dd30>: Failed to establish a new connection: [Errno 110] Connection timed out',))
I have allowed all incoming and outgoing traffic to my AWS security group in an attempt to fix this. Still to no avail.
Any help would be greatly, greatly appreciated. Cheers.
The explanation is simple: A Lambda instance running in a VPC cannot access the internet:
When you add VPC configuration to a Lambda function, it can only access resources in that VPC. If a Lambda function needs to access both VPC resources and the public Internet, the VPC needs to have a Network Address Translation (NAT) instance inside the VPC.
The solution is also simple, if annoying: run a NAT Instance or NAT Gateway in the VPC. (An alternate solution is to take your Lambda out of the VPC, but that is a much bigger change.)
I am running Django / Zappa in Lambda with a NAT instance for connecting to Amazon Simple Email Service and it works fine.

How to check (not bypass) SSL certificate with urllib2.urlopen?

I'm using Python 2.7.13. I'm trying to connect to https://www.python.org/ and verify its certificate using urllib2.urlopen. I'm getting "SSL: CERTIFICATE_VERIFY_FAILED" error in the process, and when I try to google the issue, I seem to get answers on how to bypass this security check. But I don't want my code to bypass it, I want it to use the certificate. Here's my code that fails:
import urllib2
from contextlib import closing
import ssl
ctx = ssl.create_default_context(purpose = ssl.Purpose.SERVER_AUTH, cafile = 'www.python.org.crt')
request = urllib2.Request('https://www.python.org/')
# Produces URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:661)>
with closing(urllib2.urlopen(request, context = ctx)) as response:
print response.read()
cafile = 'www.python.org.crt' is a PEM-formatted file that properly starts with -----BEGIN CERTIFICATE-----. I exported it from https://www.python.org/ using this instruction and put it into the script's working folder.
From the documentation: https://docs.python.org/2/library/ssl.html#ssl._https_verify_certificates
Starting with Python 2.7.9, httplib and modules which use it, such as urllib2 and xmlrpclib, default to verifying remote server certificates received when establishing client HTTPS connections. This default verification checks that the certificate is signed by a Certificate Authority in the system trust store and that the Common Name (or Subject Alternate Name) on the presented certificate matches the requested host.
So you don't need to anything special to verify the certificate. And you can see that because you have a validation failure, which shows you that validation is happening.
So why aren't you getting successful validation? The answer to this lies in your use of the cafile. The cafile parameter takes a file which overrides your systems default trusted certificate store. But the important thing to understand about trusted certificates the validation process isn't to check the host is in the trusted store but signed but a cert in the trusted store. So you don't need to pass in the actual server certificate, you would pass in the certificate from python.org's certificate vendors (digicert at the time of writing) .
But actually you don't even need to do this as you system should come with a large set of trusted certificates from many vendors. These vendors are audited to some extent ( Opinions vary on the extent - and this now getting off topic) and python's library will validate against this set as default if you leave the cafile parameter blank.
So you find that
>>> ctx = ssl.create_default_context(purpose = ssl.Purpose.SERVER_AUTH, cafile = '/tmp/python.org.cert')
>>> urllib2.urlopen("https://www.python.org/", context = ctx)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/urllib2.py", line 154, in urlopen
return opener.open(url, data, timeout)
File "/usr/lib/python2.7/urllib2.py", line 429, in open
response = self._open(req, data)
File "/usr/lib/python2.7/urllib2.py", line 447, in _open
'_open', req)
File "/usr/lib/python2.7/urllib2.py", line 407, in _call_chain
result = func(*args)
File "/usr/lib/python2.7/urllib2.py", line 1241, in https_open
context=self._context)
File "/usr/lib/python2.7/urllib2.py", line 1198, in do_open
raise URLError(err)
urllib2.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:661)>
fails, but this:
>>> ctx = ssl.create_default_context(purpose = ssl.Purpose.SERVER_AUTH,)
>>> urllib2.urlopen("https://www.python.org/", context = ctx)
<addinfourl at 140556044048504 whose fp = <socket._fileobject object at 0x7fd5c1127b50>>
works.
Finally I'd like to point you at httplib and http.client (in python 3) which are much cleaner interfaces for this sort of thing.

Flask-JWT generates error when Debug=False

I am playing around with Flask. I have created an API using Flask-Restful and Flask-JWT. When Debug=True in Flask, and I do not send the Authorization Header, I get the response as However, when the debug=False, the response returned is Internal Server Error with this stack trace,
[2017-01-19 19:43:10,753] ERROR in app: Exception on /api_0_1/deals [GET]
Traceback (most recent call last):
File "C:\Users\ARFATS~1\Desktop\Dealflow\venv\lib\site-packages\flask\app.py", line 1612, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\ARFATS~1\Desktop\Dealflow\venv\lib\site-packages\flask\app.py", line 1598, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "C:\Users\ARFATS~1\Desktop\Dealflow\venv\lib\site-packages\flask_restful\__init__.py", line 477, in wrapper
resp = resource(*args, **kwargs)
File "C:\Users\ARFATS~1\Desktop\Dealflow\venv\lib\site-packages\flask_jwt\__init__.py", line 176, in decorator
_jwt_required(realm or current_app.config['JWT_DEFAULT_REALM'])
File "C:\Users\ARFATS~1\Desktop\Dealflow\venv\lib\site-packages\flask_jwt\__init__.py", line 155, in _jwt_required
headers={'WWW-Authenticate': 'JWT realm="%s"' % realm})
JWTError: Authorization Required. Request does not contain an access token
I would like Flask-JWT to respond with the response which is there when Debug=True. However, I cannot use debug on Production servers. One way is to use my own jwt_required decorator. Is there any other way?Also, I would be happy to know what I am missing, if any. Thanks
You will need to add this setting to your flask app:
app.config['PROPAGATE_EXCEPTIONS'] = True
When debug is true, PROPAGATE_EXCEPTIONS is also set to true by default.
Perhaps consider checking out flask-jwt-extended instead (https://github.com/vimalloc/flask-jwt-extended), it takes care of the PROPAGATE_EXCEPTIONS for you. It aims to replace the abandoned flask-jwt library, and add some conviences when working with JWTs (such as refresh tokens, easily adding custom data to the JWTs, fresh vs non-fresh tokens, and more). Full disclosure, I'm the author of that extension.
Cheers.

Why I receive CERTIFICATE_VERIFY_FAILED from google adwords api?

Why google adwords api stops on call this link:
https://adwords.google.com/api/adwords/mcm/v201502/CustomerService?wsdl
With this error - should I load some certificate before and how?
urllib2.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590)>
Using Python 2.7.10.
Full source code:
create_adwords_client_without_yaml.py
Full error code:
Traceback (most recent call last):
File "C:/Users/Crezary Wagner/PycharmProjects/learn-adwords/src/examples/create_adwords_client_without_yaml.py", line 56, in <module>
CLIENT_CUSTOMER_ID)
File "C:/Users/Crezary Wagner/PycharmProjects/learn-adwords/src/examples/create_adwords_client_without_yaml.py", line 50, in main
customer = adwords_client.GetService('CustomerService').get()
File "C:\root\Python27\lib\site-packages\googleads\adwords.py", line 256, in GetService
proxy=proxy_option, cache=self.cache, timeout=3600)
File "C:\root\Python27\lib\site-packages\suds\client.py", line 115, in __init__
self.wsdl = reader.open(url)
File "C:\root\Python27\lib\site-packages\suds\reader.py", line 150, in open
d = self.fn(url, self.options)
File "C:\root\Python27\lib\site-packages\suds\wsdl.py", line 136, in __init__
d = reader.open(url)
File "C:\root\Python27\lib\site-packages\suds\reader.py", line 74, in open
d = self.download(url)
File "C:\root\Python27\lib\site-packages\suds\reader.py", line 92, in download
fp = self.options.transport.open(Request(url))
File "C:\root\Python27\lib\site-packages\suds\transport\https.py", line 62, in open
return HttpTransport.open(self, request)
File "C:\root\Python27\lib\site-packages\suds\transport\http.py", line 67, in open
return self.u2open(u2request)
File "C:\root\Python27\lib\site-packages\suds\transport\http.py", line 132, in u2open
return url.open(u2request, timeout=tm)
File "C:\root\Python27\lib\urllib2.py", line 431, in open
response = self._open(req, data)
File "C:\root\Python27\lib\urllib2.py", line 449, in _open
'_open', req)
File "C:\root\Python27\lib\urllib2.py", line 409, in _call_chain
result = func(*args)
File "C:\root\Python27\lib\urllib2.py", line 1240, in https_open
context=self._context)
File "C:\root\Python27\lib\urllib2.py", line 1197, in do_open
raise URLError(err)
urllib2.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590)>
Python uses certificates from 'system ssl certificate store' to certify https connection, if there is not any appropriate ssl cert in the store error occurs like this.
Download ssl certificate (Open your https link in browser and click lock icon in address bar > More Information > View Certificate > Details > Export) and install it on your system as stated this link http://windows.microsoft.com/en-us/windows/import-export-certificates-private-keys#1TC=windows-7
Not sure if that's the problem here, but worth checking it.
Python 2.7.9 enabled certificate validation by default for HTTP connections.
The server you're connecting to does not have a certificate that is trusted by your client. pysphere should configure SSL appropriately for this use case.
Try making your request like:
requests.get('https://adwords.google.com/api/adwords/mcm/v201502/CustomerService?wsdl', verify=False)
Try this, it helped me:
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
I encountered this issue. I had my phone setup using the same DNS block list and it wasn't immediately apparent after I'd enabled the tool and resumed work on this particular project. I suggest scrutinizing your setup and verify that there aren't any adblockers (DNS level in my case ala NextDNS/hosted PiHole) enabled. Hours upon hours spent trying out python versions, certificates, reinstalling things. Hope this helps someone!