Flask Mail doesn't work when deployed on Ubuntu - nginx

I'm sending password reset email with Flask-Mail. When I tried it on development server everything works fine. When deployed on Ubuntu (using NGINX, Gunicorn) sending the email leads after a long loading time to Error 502 so I don't think there's problem in sending the email rather there's a problem in the settings.
My init code after deploying:
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_login import LoginManager
from flask_mail import Mail
from flask_socketio import SocketIO
import json
with open('/etc/config.json') as config_file:
config = json.load(config_file)
app = Flask(__name__)
app.config['SECRET_KEY'] = config.get('SECRET_KEY')
app.config['SQLALCHEMY_DATABASE_URI'] = config.get('SQLALCHEMY_DATABASE_URI')
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'
login_manager.login_message_category = 'info'
app.config['MAIL_SERVER'] = 'smtp.gmail.com'
app.config['MAIL_PORT'] = 587
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USERNAME'] = config.get('EMAIL_USER')
app.config['MAIL_PASSWORD'] = config.get('EMAIL_PASS')
mail = Mail(app)
In config.json the information is correctly provided

Disabling CAPTCHA for clients
If you are not using 2-factor authentication and you have verified the credentials in your Python source are correct, follow these steps:
1.) Login to gmail in your browser
2.) Navigate to the DisplayUnclockCaptcha page.
3.) Click the continue button, and you will see the message 'Account access enabled Please try signing in to your Google account again from your new device or application.'
4.)Run your Python script - your login attempt should be successful.

Hello i might be a little late for this, but thomas your problem is caused because of linode which is probably the deployment server that you used, decided to default block the ports that you are using as you can see it here.
https://www.linode.com/community/questions/19082/i-just-created-my-first-linode-and-i-cant-send-emails-why
if u follow the process given it certainly will work

Related

Adafruit_requests library functions differently than Python requests library

So I'm trying to run a post request to a TD Ameritrade API on an adafruit Magtag device using the adafruit_requests module. I have run the same code in Python using the requests module, which has proven to work fine.
My Magtag device has successfully connected to the internet and executed the test requests adafruit supplied, but will not work with my code and returns a "duplicate headers" error. Below is the complete code that I ran on my MagTag device as well as the error message that was returned.
import ssl
import wifi
import socketpool
import adafruit_requests
import json
# Get wifi details from a secrets.py file
from secrets import secrets
# Connect to wifi
wifi.radio.connect(secrets["ssid"],secrets["password"])
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
# Get json data
refreshToken = ''
client_id = ''
with open("TDtokens.json","r") as tokens_file, open("TDsecrets.json","r") as secrets_file:
refreshToken = json.load(tokens_file)['refresh_token']
client_id = json.load(secrets_file)['client_id']
# Refresh token needs to be triggered every 30 minutes, as authToken expires.
url = r"https://api.tdameritrade.com/v1/oauth2/token"
headers = {'Content-Type':'application/x-www-form-urlencoded'}
data = {'grant_type': 'refresh_token','refresh_token': refreshToken,'client_id':client_id}
authReply = requests.post(url=url, headers=headers, data=data)
print(authReply.json())
{'fault': {'faultstring': 'Duplicate Header "Content-Type"', 'detail': {'errorcode': 'protocol.http.DuplicateHeader'}}}
I have done a lot of tweaking and I can't figure out where this error is coming from, whether from adafruit or TD Ameritrade's side. Upon reading the documentation for the adafruit_requests module I do not see any reason why an error would be raised for this type of request.
If you have any experience with adafruit or Python requests any advice would be greatly appreciated.

How to skip extra 'sign in with' page in Flask App Builder / Airflow

I have started using Apache Airflow (Built upon FAB) and enabled authentication through OAuth (as shown in FAB Security). I have ONLY one OAUTH_PROVIDER (azure).
FYI, Airflow version 2.1.4
When I launch my airflow home page, it used to open the direct login page of my OAUTH_PROVIDER.
NOW, the real problem started when I upgraded my airflow to 2.2.4 AND configured the same OAUTH (Azure) provider.
When I launch my airflow home page, a page coming like this
After clicking the button "Sign In with azure", the user login page comes.
Compared to the older airflow, the latest version got an extra page.
Why is matter to me?
We are rendering airflow in a web app and this extra "sign in with" page does not look good.
Please provide some info on SKIPPING that extra interaction.
After upgrading Airflow, Flask Appbuilder version was probably also bumped and that caused change in behavior. Basically:
Flask Appbuilder < 3.4.0 made it possible to have automatic sign-in when just one oauth provider was configured
Flask Appbuilder >= 3.4.0 changed the behavior and made it impossible to achieve this. This is the PR (with justification) that removed this functionality: https://github.com/dpgaspar/Flask-AppBuilder/pull/1707
If you want previous behavior to be used in your deployment, this is what most likely would work (although I didn't test it):
Prepare custom view class, let's call it CustomAuth0AuthView - it would bring back old behavior on login method. (I used v4.1.3 as reference code and modified it slightly).
webserver_config.py:
from flask_appbuilder.security.views import AuthOAuthView
class CustomAuthOAuthView(AuthOAuthView):
#expose("/login/")
#expose("/login/<provider>")
#expose("/login/<provider>/<register>")
def login(self, provider: Optional[str] = None) -> WerkzeugResponse:
log.debug("Provider: {0}".format(provider))
if g.user is not None and g.user.is_authenticated:
log.debug("Already authenticated {0}".format(g.user))
return redirect(self.appbuilder.get_url_for_index)
if provider is None:
if len(self.appbuilder.sm.oauth_providers) > 1:
return self.render_template(
self.login_template,
providers=self.appbuilder.sm.oauth_providers,
title=self.title,
appbuilder=self.appbuilder,
)
else:
provider = self.appbuilder.sm.oauth_providers[0]["name"]
log.debug("Going to call authorize for: {0}".format(provider))
state = jwt.encode(
request.args.to_dict(flat=False),
self.appbuilder.app.config["SECRET_KEY"],
algorithm="HS256",
)
try:
if provider == "twitter":
return self.appbuilder.sm.oauth_remotes[provider].authorize_redirect(
redirect_uri=url_for(
".oauth_authorized",
provider=provider,
_external=True,
state=state,
)
)
else:
return self.appbuilder.sm.oauth_remotes[provider].authorize_redirect(
redirect_uri=url_for(
".oauth_authorized", provider=provider, _external=True
),
state=state.decode("ascii") if isinstance(state, bytes) else state,
)
except Exception as e:
log.error("Error on OAuth authorize: {0}".format(e))
flash(as_unicode(self.invalid_login_message), "warning")
return redirect(self.appbuilder.get_url_for_index)
Prepare custom security manager. Let's call it CustomSecurityManager. It would use your custom view to handle login.
webserver_config.py:
from airflow.www.security import AirflowSecurityManager
class CustomSecurityManager(AirflowSecurityManager):
authoidview = CustomAuthOAuthView
Configure Airflow to use your CustomSecurityManager
webserver_config.py:
SECURITY_MANAGER_CLASS = CustomSecurityManager
More on this:
https://flask-appbuilder.readthedocs.io/en/latest/security.html#your-custom-security
https://developer.squareup.com/blog/secure-apache-airflow-using-customer-security-manager/

Does Airflow v1.10.3 come with Flask App builder (FAB) by default and requires Google Oauth configs in webserver_config.py?

I had a question related to Airflow v1.10.3. We recently upgraded airflow from v1.9 to v1.10.3. With the new upgrade, we are experiencing a situation where any Celery execute commands coming in from the UI are not getting queued/executed in message broker and celery workers.
Based on Celery FAQ: https://docs.celeryproject.org/en/latest/faq.html#why-is-task-delay-apply-the-worker-just-hanging, it points to authentication issue, user not having the access.
We had web authentication (Google Oauth) in place in version v1.9 using following config:
[webserver]:
authenticate = True
auth_backend = airflow.contrib.auth.backends.google_auth
[google]:
client_id = <client id>
client_secret = <secret key>
oauth_callback_route = /oauth2callback
domain = <domain_name>.com
Will the above config values still work or do we need to set the RBAC=True and provide Google Oauth credentials in webserver_config.py?
Webserver_config.py
from flask_appbuilder.security.manager import AUTH_OAUTH
AUTH_TYPE = AUTH_OAUTH
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = "Admin"
OAUTH_PROVIDERS = [{
'name':'google',
'whitelist': ['#yourdomain.com'], # optional
'token_key':'access_token',
'icon':'fa-google',
'remote_app': {
'base_url':'https://www.googleapis.com/oauth2/v2/',
'request_token_params':{
'scope': 'email profile'
},
'access_token_url':'https://oauth2.googleapis.com/token',
'authorize_url':'https://accounts.google.com/o/oauth2/auth',
'request_token_url': None,
'consumer_key': '<your_client_id>',
'consumer_secret': '<your_client_secret>',
}
}]
Any help is very much appreciated. Thanks.
From my experience, both will work. Of course, as they call the FAB-based UI, the "new UI", the old one will probably be killed off.
Your problem, though, doesn't sound like it has anything to do with user authentication, but celery access. It sounds like airflow and/or celery are not reading celery_result_backend or one of the other renamed options, when they should.
Search for Celery config in their UPDATING document for the full list.

python http lib automatically determine the type of authentication

I have a problem that I known the web services require authentication,but I can't determine Basic or Digest it need,How can I deal with this situation use python2.7 http library that I have own the username and password?
You should use requests.It has requests_toolbelt lib for auto check authentication type,the following sample code:
import requests
import requests_toolbelt
auth = requests_toolbelt(username,password)
req = requests.get(url,auth=auth)

Openstack: login as admin and retrieve server data from different tenants via python

I'm writing some cron job in python for Openstack that should read server ids from a database and then get the servers from the API by using the python-novaclient.
In pseudo code things should work like this:
session = login_to_keystone(user="admin", password="something") #or use a token
nova_client = get_nova_client(session)
#the servers array holds dictionaries with server, user and tenant ids as strings
# e.g. {"server_id": "1-2-3", "tentant_id": "456", user_id: "11111-2222"}
for server in servers:
server_obj = nova_client.servers.get(server.server_id)
...do stuff with server_obj (read data from it, delete,...)...
What I've come up with is the following, but it's not right as I get a EndpointNotFound exception. I'm using Devstack with Juno.
from keystoneclient.v2_0 import client as keystone_client
from keystoneclient import session
from novaclient import client as nova_client
#the url is the admin endpoint
keystone = keystone_client.Client(token="my-admin-token",
auth_url="http://192.168.1.1:35357/v2.0",
endpoint="http://192.168.1.1:35357/v2.0")
key_session = session.Session(auth=keystone)
nova = nova_client.Client(2, session=key_session)
#let's assume the servers array is already populated
for server in servers:
server_obj = nova.servers.get(server.server_id) #Exception happens here
I need to run this as admin as servers can belong to any tenant and they might even be deleted by the cron job.
Thanks for any help!
UPDATE:
The information I need was that I can use the admin tenant for retrieving all servers (regardless of their owner). This allows me also to use the publicURL.
My current solution looks like this:
from keystoneclient.auth.identity import v2
from keystoneclient import session
from novaclient import client as nova_client
auth = v2.Password(auth_url="http://192.168.1.1:5000/v2.0",
username="admin",
password="my_secrete",
tenant_name="admin") # the admin's tenant
auth_session = session.Session(auth=auth)
nova = nova_client.Client(2, session=auth_session)
for server in servers:
... do stuff like nova.servers.get("some id")
In order to get a list of servers from all tenants, you need to perform two tasks:
Log in as a user with admin privileges, and
Tell the Nova API that you want a list of servers for all tenants.
Logging in as an admin user
It looks like you're trying to use the admin_token defined in keystone.conf for authentication. This may work, but this mechanism is meant primarily as a means of bootstrapping Keystone. When interacting with the other services, you are meant to log in using a username/password pair that has been defined in Keystone with admin credentials. I think that what #anoop.babu has given you will work just fine:
>>> nova = nova_client.Client('2', USERNAME, PASSWORD,
PROJECT_ID, AUTH_URL)
Where:
USERNAME = admin
PASSWORD = password_for_admin_user
PROJECT_ID = admin
AUTH_URL = http://your_api_server:5000/v2.0
We can test this client out using something like:
>>> nova.hypervisors.list()
[<Hypervisor: 2>]
That tells us we've authenticated successfully.
Listing all servers
If we simply called nova.servers.list(), we are asking for a list of Nova servers owned by the admin tenant, which should generally be empty:
>>> nova.servers.list()
[]
In order to see servers from other tenants, you need to pass the all_tenants search option:
>>> nova.servers.list(search_opts={'all_tenants':1})
[<Server: cirros0>]
And that should get you where you want to be.
Here you have given auth_url as your endpoint. endpoint is actually the publicURL of the service.
You can find the publicURL using the below CLI Command
nova endpoints
and check for keystone details.
You can also get an authenticated keystone object using below api version without using endpoint,
import keystoneclient.v2_0.client as keystone_client
keystone = keystone_client.Client(auth_url = my_auth_url , username = my_user_name , password = my_password , tenant_name = my_tenant_name )
And create a session object as below,
from keystoneclient import session
key_session = session.Session(auth=keystone)
An alternate and simplified approach to get nova client authorized without keystone is,
from novaclient import client as nova_client
nova = nova_client.Client('2', USERNAME, PASSWORD, PROJECT_ID, AUTH_URL)
server_obj = nova.servers.find( name=my_server_name )

Resources