How can I authenticate web socket connection in postman? - python

This is my ASGI file:
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
import os
import app.routing
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project.settings")
application = get_asgi_application()
application = ProtocolTypeRouter({
'http': get_asgi_application(),
"websocket": AuthMiddlewareStack(
URLRouter(
app.routing.websocket_urlpatterns
)
),
})
This is my routing.py file:
from django.urls import path
from . import consumers
websocket_urlpatterns = [
path('ws/sc/', consumers.MySyncConsumer.as_asgi()),
path('ws/ac/', consumers.MyASyncConsumer.as_asgi()),
path('ws/test/', consumers.TestConsumer.as_asgi()),
path('ws/scg/', consumers.MySyncGroupConsumer.as_asgi()),
]
This is my consumer file:
class MySyncConsumer(SyncConsumer):
def websocket_connect(self,event):
print("Web socket connected", event)
self.send({
'type':'websocket.accept'
})
print("Channel layer ",self.channel_layer)
print("Channel name", self.channel_name)
async_to_sync(self.channel_layer.group_add)("test_consumer_group_1", self.channel_name)
def websocket_receive(self,event):
print("Web socket recieved",event)
print(event["text"])
async_to_sync(self.channel_layer.group_send)("test_consumer_group_1", {
'type':'chat.message',
'message':event['text']
})
#event handler, whuch is sending data to client
def chat_message(self,event):
print('Event...', event)
print('Event...', event["message"])
self.send({
"type":"websocket.send",
"text":event['message']
})
def send_notification(self, event):
print("send_notification called")
print('Event...', event['value'])
self.send({
"type":"websocket.send",
"text":event['value']
})
def websocket_disconnect(self,event):
print("Web socket disconnect", event)
async_to_sync(self.channel_layer.group_discard)("test_consumer_group_1", self.channel_name)
raise StopConsumer()
How can I authenticate web socket connection in postman? I want to authenticate web socket connection so that self.scope["user"] returns currently logged in user in consumers.py. Otherwise it returns an anonymous user.

Related

In authlib, does authorize_access_token require the explicit passing of client_id and client_secret?

I am using authlib with a pretty standard OAuth2 flow.
import pickle
import json
import os.path
from requests.models import Response
from authlib.integrations.flask_client import OAuth, OAuthError
class BaseApi(object):
def __init__(self, oauth_client, config_directory, token_file=''):
self.oauth_client = oauth_client
if token_file:
self.token_file = token_file
else:
self.token_file = os.path.join(config_directory, 'token.pickle')
#property
def token(self):
try:
print ("Token: %s" % self.__token)
return self.__token
except AttributeError:
if os.path.exists(self.token_file):
with open(self.token_file, 'rb') as f:
self.__token = pickle.load(f)
print ("Pickled Token: %s" % self.token)
return self.__token
#token.setter
def token(self, new_token):
self.__token = new_token
# The authorizaiton flow sends us to the OAuth provider
# with a redirect back to our app
def login(self, state=None):
return self.oauth_client.authorize_redirect(self.auth_callback, state=state)
# Our authorized endpoint.
def authorized(self,request):
# Get the access token!
token = self.oauth_client.authorize_access_token(client_id=self.oauth_client.client_id,
client_secret=self.oauth_client.client_secret)
#if resp is None or resp.get('access_token') is None:
# return 'Access denied: error=%s resp=%s' % (
# request.args,
# resp
# )
self.token = token
This is all subclassed in a different module:
from __future__ import print_function
import json
from backend.oauth_base import BaseApi, OAuth, load_credentials_file
from urllib.parse import urlparse
from backend import app, url_for # This is the flask app
from flask import request, redirect, jsonify
import requests
import os
config_directory = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'config')
class BasecampApi(BaseApi):
def __init__(self):
oauth = OAuth(app)
credentials = load_credentials_file(os.path.join(config_directory,
'credentials.json'))
oauth.register(
name='basecamp',
client_id=credentials['client_id'],
client_secret=credentials['client_secret'],
api_base_url='https://3.basecampapi.com/',
request_token_url=None,
request_token_params={'type': 'web_server'},
access_token_url='https://launchpad.37signals.com/authorization/token',
access_token_params={'type': 'web_server'},
authorize_url='https://launchpad.37signals.com/authorization/new',
authorize_params={'type': 'web_server'}
)
oauth_client = oauth.create_client('basecamp')
super().__init__(oauth_client, config_directory)
Everything here works, but I'm confused as to why I need to pass client_id and client_secret explicitly in the authorize access token.
token = self.oauth_client.authorize_access_token()
Causes the basecamp API to throw an error complaining about a lack of clien_id (and then client_secret).
This is different from the docs (which I admittedly found confusing). Is this the expected behavior?
The default token_endpoint_auth_method is client_secret_basic, which will send client credentials in HTTP Authorization header. However, according to your description, it seems that the provider needs client_id and client_secret in payload, which should be client_secret_post. Consider to add below client_kwargs into your .register:
client_kwargs = {
'token_endpoint_auth_method': 'client_secret_post',
}

Twitter Account Activity API - 'code': 214, 'message': 'Non-200 response code during CRC GET request (i.e. 404, 500, etc).'

I was using a sample app, that manages Tweeter Account Activity API, here's the link:
https://github.com/RickRedSix/twitter-webhook-boilerplate-python/blob/master/Main.py
I built my web app in pythonanywhere.com and I keep getting this:
{error : {'code': 214, 'message': 'Non-200 response code during CRC GET request (i.e. 404, 500, etc).'}}
In my wsgi configuration the code goes as follows
# This file contains the WSGI configuration required to serve up your
# web application at http://<your-username>.pythonanywhere.com/
# It works by setting the variable 'application' to a WSGI handler of some
# description.
#
# The below has been auto-generated for your Flask project
import sys
# add your project directory to the sys.path
project_home = '/home/YouMatterBot2/mysite'
if project_home not in sys.path:
sys.path = [project_home] + sys.path
# import flask app but need to call it "application" for WSGI to work
from flask_app import app as application # noqa
Here's the code in the flask_app.py:
#!/usr/bin/env python
from flask import Flask, request, send_from_directory, make_response
from http import HTTPStatus
import Twitter, hashlib, hmac, base64, os, logging, json
from dotenv import load_dotenv
load_dotenv('.env')
CONSUMER_SECRET = os.getenv('CONSUMER_SECRET')
CURRENT_USER_ID = os.getenv('CURRENT_USER_ID')
app = Flask(__name__)
#generic index route
#app.route('/')
def default_route():
return send_from_directory('www', 'index.html')
#The GET method for webhook should be used for the CRC check
#TODO: add header validation (compare_digest https://docs.python.org/3.6/library/hmac.html)
#app.route("/webhook", methods=["GET"])
def twitterCrcValidation():
crc = request.args['crc_token']
validation = hmac.new(
key=bytes(CONSUMER_SECRET, 'utf-8'),
msg=bytes(crc, 'utf-8'),
digestmod = hashlib.sha256
)
digested = base64.b64encode(validation.digest())
response = {
'response_token': 'sha256=' + format(str(digested)[2:-1])
}
print('responding to CRC call')
return json.dumps(response)
#The POST method for webhook should be used for all other API events
#TODO: add event-specific behaviours beyond Direct Message and Like
#app.route("/webhook", methods=["POST"])
def twitterEventReceived():
requestJson = request.get_json()
#dump to console for debugging purposes
print(json.dumps(requestJson, indent=4, sort_keys=True))
if 'favorite_events' in requestJson.keys():
#Tweet Favourite Event, process that
likeObject = requestJson['favorite_events'][0]
userId = likeObject.get('user', {}).get('id')
#event is from myself so ignore (Favourite event fires when you send a DM too)
if userId == CURRENT_USER_ID:
return ('', HTTPStatus.OK)
Twitter.processLikeEvent(likeObject)
elif 'direct_message_events' in requestJson.keys():
#DM recieved, process that
eventType = requestJson['direct_message_events'][0].get("type")
messageObject = requestJson['direct_message_events'][0].get('message_create', {})
messageSenderId = messageObject.get('sender_id')
#event type isnt new message so ignore
if eventType != 'message_create':
return ('', HTTPStatus.OK)
#message is from myself so ignore (Message create fires when you send a DM too)
if messageSenderId == CURRENT_USER_ID:
return ('', HTTPStatus.OK)
Twitter.processDirectMessageEvent(messageObject)
else:
#Event type not supported
return ('', HTTPStatus.OK)
return ('', HTTPStatus.OK)
if __name__ == '__main__':
# Bind to PORT if defined, otherwise default to 65010.
port = int(os.environ.get('PORT', 65010))
gunicorn_logger = logging.getLogger('gunicorn.error')
app.logger.handlers = gunicorn_logger.handlers
app.logger.setLevel(gunicorn_logger.level)
app.run(host='0.0.0.0', port=port, debug=True)
but when I run the this code to register my webhook
from TwitterAPI import TwitterAPI
import os
from dotenv import load_dotenv
load_dotenv('.env')
CONSUMER_KEY = os.getenv('CONSUMER_KEY')
CONSUMER_SECRET = os.getenv('CONSUMER_SECRET')
ACCESS_TOKEN = os.getenv('ACCESS_TOKEN')
ACCESS_TOKEN_SECRET = os.getenv('ACCESS_TOKEN_SECRET')
#The environment name for the beta is filled below. Will need changing in future
ENVNAME = os.getenv('ENVNAME')
WEBHOOK_URL = os.getenv('WEBHOOK_URL')
twitterAPI = TwitterAPI(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
r = twitterAPI.request('account_activity/all/:%s/webhooks' % ENVNAME, {'url': WEBHOOK_URL})
print (r.status_code)
print(r.json())
print (r.text)
I get the said error.
Is this a problem because of pythonanywhere.com, if so how can I fix it?

Twilio not working - after connecting with Database [on pythonanywhere]

Hi I want to create a chatbot to gather user's information and store user inputs in MySQL database. I followed this tutorial and everything worked but after implementing database connection, I couldn't access it via Twilio SMS. I can still check the chatbot flow from dialogflow but twilio is not responding. Here is the code.. it was big so couldn't share the whole webhook function. Please tell me how to connect with database.. seems like dialogflow inbuilt chatbot is working fine but my main motive is to work from Twilio SMS. How to establish that?
P.s. before database connection, it was working fine just like in the tutorial.
import json
import apiai
import os
from flask import Flask
from twilio.rest import Client
from twilio.http.http_client import TwilioHttpClient
from flask import request, make_response, jsonify
# Twilio account info
account_sid = "_####__"
auth_token = "_###__"
account_num = "+_###__"
proxy_client = TwilioHttpClient()
proxy_client.session.proxies = {'https': os.environ['https_proxy']}
client = Client(account_sid, auth_token, http_client=proxy_client)
# api.ai account info
CLIENT_ACCESS_TOKEN = "_###__"
ai = apiai.ApiAI(CLIENT_ACCESS_TOKEN)
app = Flask(__name__)
# ---database handling starts-----
# create a MySQL client connecting to your MySQL server
import mysql.connector
mydb = mysql.connector.connect(
host="---###---",
user="---###---",
passwd="---###---",
database="---###---"
)
mycursor = mydb.cursor()
# ----webhook method calling----
#app.route('/', methods=['POST'])
def webhook():
global counting_id
req = request.get_json(silent=True, force=True)
action = req.get('queryResult').get('action')
# WEBHOOK CODE
# return make_response(jsonify({"speech": res}))
#app.route('/hello')
def hello_world():
return 'Hello api.ai (from Flask!)'
#app.route("/", methods=['GET', 'POST'])
def server():
from flask import request
# get SMS metadata
msg_from = request.values.get("From", None)
msg = request.values.get("Body", None)
# print(msg)
# print('msg_from=', msg_from)
# prepare API.ai request
req = ai.text_request()
req.lang = 'en' # optional, default value equal 'en'
req.query = msg
# req.session_id = msg_from
# print(ai)
# print(req)
# get response from API.ai
api_response = req.getresponse()
responsestr = api_response.read().decode('utf-8')
response_obj = json.loads(responsestr)
reply="Hello [reply from flask]"
if 'result' in response_obj:
response = response_obj["result"]["fulfillment"]["speech"]
# send SMS response back via twilio
reply=client.messages.create(to=msg_from, from_= account_num, body=response)
return str(reply)
if __name__ == "__main__":
app.run(debug=True)

Google API + Service Account for impersonate user

What I'm traing to do is to get all the members of a single group, and then download all the emails headers they have in gmail. To do this I started with google gmail api and members api, but i get stuck. I realice that I can't do it even if I have admin role.
What i found is that the right way to do it (I think...) is to use a service account for impersonate user. What i done:
Create a new project.
Create service account credentials.
Add Domain-wide Delegation to the service account.
Enable scopes for this proyect.
The code to create the service:
from __future__ import print_function
from googleapiclient.discovery import build
from httplib2 import Http
from oauth2client import file, client, tools
from google.oauth2 import service_account
import requests
import json
class Service:
SCOPES = ['https://mail.google.com/',
'https://sites.google.com/feeds',
'https://www.google.com/m8/feeds',
'https://www.googleapis.com/auth/activity',
'https://www.googleapis.com/auth/calendar',
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/gmail.settings.basic',
'https://www.googleapis.com/auth/gmail.settings.sharing',
'https://www.googleapis.com/auth/plus.login',
'https://www.googleapis.com/auth/plus.me',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/admin.directory.group',
'https://www.googleapis.com/auth/gmail.metadata'
]
secret_file = 'client-secret.json'
service = ''
service_name = ''
service_version = ''
delegated_credentials = ''
credentials = ''
def __init__(self, servicename, serviceversion):
self.service_name = servicename
self.service_verion = serviceversion
self.newService()
def newService(self):
self.credentials = service_account.Credentials.from_service_account_file(self.secret_file, scopes=self.SCOPES)
self.credentials = self.credentials.with_subject('admin#domain.com')
self.service = build(self.service_name, self.service_verion, credentials=self.credentials)
return self.service
if __name__ == '__main__':
main()
Members class:
from __future__ import print_function
from googleapiclient.discovery import build
from httplib2 import Http
from oauth2client import file, client, tools
from service import Service
import requests
import json
class Members:
service = ''
group_name = ''
members = []
def __init__(self, groupname):
self.group_name = groupname
self.service = Service('admin', 'directory_v1')
def get_members(self):
print('Buscando los miembros del grupo')
results = self.service.service.members().list(groupKey=self.group_name).execute()
for member in results['members']:
print('Descargando datos de: ', member['email'])
self.members.append(member['id'])
return self.members
if __name__ == '__main__':
main()
app.py:
from __future__ import print_function
from googleapiclient.discovery import build
from httplib2 import Http
from oauth2client import file, client, tools
from members import Members
from user import User
from service import Service
import requests
def main():
member = Members("group#ldomain.com")
members_list = member.get_members()
for member in members_list:
print(member)
user = User(member)
messages = user.get_user_inbox()
user.get_message_info(messages)
if __name__ == '__main__':
main()
The error I have:
"Client is unauthorized to retrieve access tokens using this method,
or client not authorized for any of the scopes requested."

Insert a file to google drive using google app engine. python client api used

Using Google App Engine, I am trying to insert a file "a.txt" into my google drive. The error that i get when i view page source of InsertDrive page is
HttpError 401 "Login Required"
bound method InsertDrive.error of main.InsertDrive object at 0x10f884b0
Note: I am calling class InsertDrive from my MainHandler Class by showing the url in the Jinja template for the MainHandler class.
import httplib2
import logging
import os
import sys
from os import path
from apiclient.discovery import build
from apiclient.http import MediaFileUpload
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client.tools import run
from apiclient import discovery
from oauth2client import appengine
from oauth2client import client
from google.appengine.api import memcache
from apiclient import errors
from apiclient.http import MediaFileUpload
import webapp2
import jinja2
CREDENTIAL = 'drive.credential'
CLIENT_SECRET_JSON = 'client_secrets.json'
SCOPE = 'https://www.googleapis.com/auth/drive'
FILE_NAME = 'a.txt'
JINJA_ENVIRONMENT = jinja2.Environment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
autoescape=True,
extensions=['jinja2.ext.autoescape'])
CLIENT_SECRETS = os.path.join(os.path.dirname(__file__), 'client_secrets.json')
MISSING_CLIENT_SECRETS_MESSAGE = """
Warning: Please configure OAuth 2.0
""" % CLIENT_SECRETS
http = httplib2.Http(memcache)
service = discovery.build('drive', 'v2', http=http)
decorator = appengine.oauth2decorator_from_clientsecrets(
CLIENT_SECRETS,
scope=[
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/drive.appdata',
'https://www.googleapis.com/auth/drive.apps.readonly',
'https://www.googleapis.com/auth/drive.file',
'https://www.googleapis.com/auth/drive.metadata.readonly',
'https://www.googleapis.com/auth/drive.readonly',
'https://www.googleapis.com/auth/drive.scripts',
],
message=MISSING_CLIENT_SECRETS_MESSAGE)
title="a.txt"
description="none"
mime_type="text/*"
filename="a.txt"
parent_id=None
class MainHandler(webapp2.RequestHandler):
#decorator.oauth_aware
def get(self):
insert_url = "/InsertDrive"
if not decorator.has_credentials():
url = decorator.authorize_url()
self.redirect(url)
self.response.write("Hello")
#variables = {
# 'url': decorator.authorize_url(),
# 'has_credentials': decorator.has_credentials(),
# 'insert_url': "/InsertDrive"
# }
template = JINJA_ENVIRONMENT.get_template('main.html')
self.response.write(template.render(insert_url=insert_url))
class InsertDrive(webapp2.RequestHandler):
# ADDED FUNCTION TO UPLOAD #
def get(self):
self.response.out.write('<h1>entered</h1>')
media_body = MediaFileUpload(filename, mimetype=mime_type, resumable=True)
self.response.write(media_body)
body = {
'title': title,
'description': description,
'mimeType': mime_type
}
self.response.write(body)
# Set the parent folder.
if parent_id:
body['parents'] = [{'id': parent_id}]
self.response.write(parent_id)
try:
file = service.files().insert(
body=body,
media_body=media_body).execute()
self.response.write(file)
# Uncomment the following line to print the File ID
# print 'File ID: %s' % file['id']
except errors.HttpError , error:
self.response.write('<h1>checking if error</h1>: %s' % error)
self.response.write(self.error)
print 'An error occured: %s' % error
app = webapp2.WSGIApplication(
[
('/', MainHandler),
('/InsertDrive' , InsertDrive),
(decorator.callback_path, decorator.callback_handler()),
],
debug=True)
Any help would be greatly appreciated
Thanks,
kira_111
i tried your code and the problem is fixed if when u try to upload the file
instead of using this code
file = service.files().insert(
body=body,
media_body=media_body).execute()
you use this
file = service.files().insert(
body=body,
media_body=media_body).execute(http=decorator.http())
the difference is that you specify that the credentials that will be used for the upload
are the ones that you have authenticated using the decorator.
Hope it helps

Categories