def test_oauth2(app, user, oauth2_client): client_id, client_secret = oauth2_client client = WebApplicationClient(client_id) host = "https://localhost" state = "randomly_text" with app.test_client() as provider: # login forcefully. with provider.session_transaction() as sess: sess["user_id"] = user sess["_fresh"] = True uri = client.prepare_request_uri(host + "/oauth2/authorize", redirect_uri=redirect_uri, state=state) uri = uri[len(host) :] # step 1: redirect to provider response = provider.get(uri, follow_redirects=True) assert response.status_code == 200 # step 2: redirect to client response = provider.post(uri, data={"scope": "user", "confirm": "yes"}) assert response.location.startswith(redirect_uri) data = client.parse_request_uri_response(response.location, state=state) assert "code" in data # step 3: get the token body = client.prepare_request_body(code=data["code"], redirect_uri=redirect_uri) response = provider.post("/oauth2/token", content_type="application/x-www-form-urlencoded", data=body) assert response.status_code == 200 data = client.parse_request_body_response(response.data) assert "access_token" in data assert data["token_type"] == "Bearer" assert data["scope"] == ["user"] # step 4: using token pass
def test_parse_token_response(self): client = WebApplicationClient(self.client_id) # Parse code and state response = client.parse_request_body_response(self.token_json, scope=self.scope) self.assertEqual(response, self.token) self.assertEqual(client.access_token, response.get("access_token")) self.assertEqual(client.refresh_token, response.get("refresh_token")) self.assertEqual(client.token_type, response.get("token_type")) # Mismatching state self.assertRaises(Warning, client.parse_request_body_response, self.token_json, scope="invalid") os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = '1' token = client.parse_request_body_response(self.token_json, scope="invalid") self.assertTrue(token.scope_changed) scope_changes_recorded = [] def record_scope_change(sender, message, old, new): scope_changes_recorded.append((message, old, new)) signals.scope_changed.connect(record_scope_change) try: client.parse_request_body_response(self.token_json, scope="invalid") self.assertEqual(len(scope_changes_recorded), 1) message, old, new = scope_changes_recorded[0] self.assertEqual(message, 'Scope has changed from "invalid" to "/profile".') self.assertEqual(old, ['invalid']) self.assertEqual(new, ['/profile']) finally: signals.scope_changed.disconnect(record_scope_change) del os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE']
class TestOauthlib(ApprovalTestCase): def setUp(self): super(TestOauthlib, self).setUp() self.libclient = WebApplicationClient(self.oauth_client.id) self.authorization_code.response_type = "code" self.authorization_code.save() def test_flow(self): self.client.login(username="******", password="******") request_uri = self.libclient.prepare_request_uri( "https://localhost" + reverse("oauth2_authorize"), redirect_uri=self.redirect_uri.url, scope=["test", ], state="test_state", ) response = self.client.get(request_uri[17:]) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, "doac/authorize.html") approval_url = reverse("oauth2_approval") + "?code=" + self.authorization_code.token response = self.client.post(approval_url, { "code": self.authorization_code.token, "code_state": "test_state", "approve_access": None, }) response_uri = response.get("location", None) if not response_uri: response_uri = response.META["HTTP_LOCATION"] response_uri = response_uri.replace("http://", "https://") data = self.libclient.parse_request_uri_response(response_uri, state="test_state") authorization_token = data["code"] request_body = self.libclient.prepare_request_body( client_secret=self.oauth_client.secret, code=authorization_token, ) post_dict = {} for pair in request_body.split('&'): key, val = pair.split('=') post_dict[key] = val response = self.client.post(reverse("oauth2_token"), post_dict) data = self.libclient.parse_request_body_response(response.content)
def test_prepare_authorization_requeset(self): client = WebApplicationClient(self.client_id) url, header, body = client.prepare_authorization_request( self.uri, redirect_url=self.redirect_uri, state=self.state, scope=self.scope) self.assertURLEqual(url, self.uri_authorize_code) # verify default header and body only self.assertEqual(header, {'Content-Type': 'application/x-www-form-urlencoded'}) self.assertEqual(body, '')
def test_parse_token_response(self): client = WebApplicationClient(self.client_id) # Parse code and state response = client.parse_request_body_response(self.token_json, scope=self.scope) self.assertEqual(response, self.token) self.assertEqual(client.access_token, response.get("access_token")) self.assertEqual(client.refresh_token, response.get("refresh_token")) self.assertEqual(client.token_type, response.get("token_type")) # Mismatching state self.assertRaises(Warning, client.parse_request_body_response, self.token_json, scope="invalid")
def authorize(self): scope = [ 'https://www.googleapis.com/auth/youtube.upload', 'https://www.googleapis.com/auth/youtube', 'https://www.googleapis.com/auth/youtubepartner' ] client = WebApplicationClient(self.registry['google_oauth_id']) self.req.response.redirect(client.prepare_request_uri( 'https://accounts.google.com/o/oauth2/auth', scope=scope, redirect_uri='%s/authorize-google' % self.site.absolute_url(), approval_prompt='force', access_type='offline', include_granted_scopes='true'))
def test_parse_grant_uri_response(self): client = WebApplicationClient(self.client_id) # Parse code and state response = client.parse_request_uri_response(self.response_uri, state=self.state) self.assertEqual(response, self.response) self.assertEqual(client.code, self.code) # Mismatching state self.assertRaises(errors.MismatchingStateError, client.parse_request_uri_response, self.response_uri, state="invalid")
def setUp(self): super(TestOauthlib, self).setUp() self.libclient = WebApplicationClient(self.oauth_client.id) self.authorization_code.response_type = "code" self.authorization_code.save()
def stripe_authorize(request, forening_id): # In order to keep the current forening_id in the callback URL, we'll have # to save it in the session request.session['admin.foreninger.stripe-connect.active-forening'] = forening_id forening = Forening.objects.get(id=forening_id) # Only admin are allowed to connect a Stripe account if not request.user.is_admin_in_forening(forening): raise PermissionDenied # Prepare Stripe OAuth 2.0 request URI using our oauth client library client = WebApplicationClient(settings.STRIPE_TOKEN['client_id']) params = { 'scope': 'read_write', 'stripe_landing': 'register', 'redirect_uri': 'https://%s%s' % ( request.site.domain, reverse('admin:foreninger.stripe_callback')), 'stripe_user[url]': forening.get_active_url(), 'stripe_user[phone_number]': forening.phone, 'stripe_user[business_name]': forening.name, 'stripe_user[business_type]': 'non_profit', 'stripe_user[physical_product]': 'false', 'stripe_user[product_category]': 'tourism_and_travel', 'stripe_user[product_description]': 'Trekking, lodging, outdoor activities', 'stripe_user[currency]': 'nok', 'stripe_user[country]': 'NO', 'stripe_user[street_address]': forening.post_address, 'stripe_user[zip]': forening.zipcode.zipcode if forening.zipcode is not None else '', 'stripe_user[city]': forening.zipcode.area if forening.zipcode is not None else '', 'stripe_user[email]': request.user.get_sherpa_email(), 'stripe_user[first_name]': request.user.get_first_name(), 'stripe_user[last_name]': request.user.get_last_name(), 'stripe_user[dob_day]': request.user.get_birth_date().day, 'stripe_user[dob_month]': request.user.get_birth_date().month, 'stripe_user[dob_year]': request.user.get_birth_date().year, } stripe_request_uri = client.prepare_request_uri( settings.STRIPE['endpoints']['authorize'], **params) return redirect(stripe_request_uri)
def test_populate_attributes(self): client = WebApplicationClient(self.client_id) response_uri = (self.response_uri + "&access_token=EVIL-TOKEN" "&refresh_token=EVIL-TOKEN" "&mac_key=EVIL-KEY") client.parse_request_uri_response(response_uri, self.state) self.assertEqual(client.code, self.code) # We must not accidentally pick up any further security # credentials at this point. self.assertIsNone(client.access_token) self.assertIsNone(client.refresh_token) self.assertIsNone(client.mac_key)
def login_view(request): client = WebApplicationClient(VK_APP_ID) vk_uri = client.prepare_request_uri('https://oauth.vk.com/authorize', scope=['notify'], redirect_uri='http://localhost/vk_register', v='5.17') context = {'vk_uri': vk_uri} ''' На FaceBook времени не хватило вообщем client = WebApplicationClient(FACEBOOK_APP_ID) fb_uri = client.prepare_request_uri('https://www.facebook.com/dialog/oauth', redirect_uri='http://localhost/fb_register') ''' context = {'vk_uri': vk_uri, 'fb_uri': '#'} return render(request, 'tvevt/login.html', context)
def index(request): client = WebApplicationClient(settings.GITHUB_CLIENT_ID) if not request.GET.has_key('code'): # todo - also setup hook for repo # todo - check http referrer = 'https://github.com/' uri = client.prepare_request_uri(AUTHORIZATION_URL, redirect_uri=request.build_absolute_uri(reverse('index')), scope=['repo']) context = {'uri': uri} else: code = request.GET['code'] body = client.prepare_request_body(code=code, client_secret=settings.GITHUB_CLIENT_SECRET) headers = {'Accept': 'application/json'} response = requests.post(REQUEST_TOKEN_URL, body, headers=headers) response = response.json() owner = Github(response['access_token']).get_user() # todo - check if user already exists => show repo settings token = GithubToken(owner=owner.login, access_token=response['access_token'], scope=response['scope']) token.save() context = {'owner': owner.name} return render(request, 'benchmarks/index.html', context)
def test_request_body(self): client = WebApplicationClient(self.client_id, code=self.code) # Basic, no extra arguments body = client.prepare_request_body(body=self.body) self.assertFormBodyEqual(body, self.body_code) rclient = WebApplicationClient(self.client_id) body = rclient.prepare_request_body(code=self.code, body=self.body) self.assertFormBodyEqual(body, self.body_code) # With redirection uri body = client.prepare_request_body(body=self.body, redirect_uri=self.redirect_uri) self.assertFormBodyEqual(body, self.body_redirect) # With extra parameters body = client.prepare_request_body(body=self.body, **self.kwargs) self.assertFormBodyEqual(body, self.body_kwargs)
def test_auth_grant_uri(self): client = WebApplicationClient(self.client_id) # Basic, no extra arguments uri = client.prepare_request_uri(self.uri) self.assertURLEqual(uri, self.uri_id) # With redirection uri uri = client.prepare_request_uri(self.uri, redirect_uri=self.redirect_uri) self.assertURLEqual(uri, self.uri_redirect) # With scope uri = client.prepare_request_uri(self.uri, scope=self.scope) self.assertURLEqual(uri, self.uri_scope) # With state uri = client.prepare_request_uri(self.uri, state=self.state) self.assertURLEqual(uri, self.uri_state) # With extra parameters through kwargs uri = client.prepare_request_uri(self.uri, **self.kwargs) self.assertURLEqual(uri, self.uri_kwargs)
def create_app(): """ Create the todo app Returns: app: The flask application. """ app = Flask(__name__) app.config.from_object('todo_app.flask_config.Config') app.config['LOGIN_DISABLED'] = os.getenv('LOGIN_DISABLED') == 'True' login_manager = LoginManager() oauth_client_id = os.environ['OAUTH_CLIENT_ID'] oauth_client_secret = os.environ['OAUTH_CLIENT_SECRET'] client = WebApplicationClient(oauth_client_id) @login_manager.unauthorized_handler def unauthenticated(): oauth_get_uri = client.prepare_request_uri( uri="https://github.com/login/oauth/authorize", state="todoapp") return redirect(oauth_get_uri, code=302) @login_manager.user_loader def load_user(user_id): return User(id=user_id, role=user_id_to_role.get(str(user_id), Role.READER)) login_manager.init_app(app) @app.route('/') @authorised_role(role=Role.READER) @login_required def index(): items = get_items() items_view_model = ItemsViewModel(items) return render_template('index.html', view_model=items_view_model, user=current_user, login_disabled=app.config['LOGIN_DISABLED']) @app.route('/login/callback') def login_callback(): code = request.args.get("code") post_token_request = client.prepare_token_request( "https://github.com/login/oauth/access_token", state="todoapp", client_id=oauth_client_id, client_secret=oauth_client_secret, code=code) (post_token_url, post_token_headers, post_token_body) = post_token_request post_token_headers["Accept"] = "application/json" token_response = requests.post(post_token_url, data=post_token_body, headers=post_token_headers) client.parse_request_body_response(token_response.text) (get_user_url, get_user_headers, _) = client.add_token("https://api.github.com/user") user_response = requests.get(get_user_url, headers=get_user_headers).json() user_id = user_response["id"] user = User(id=user_response["id"], role=user_id_to_role.get(user_id, Role.READER)) login_user(user) return redirect('/') @app.route('/todos', methods=['POST']) @authorised_role(role=Role.WRITER) @login_required def add_todo(): title = request.form.get('title') add_item(title) return redirect('/') @app.route('/todos/<id>', methods=['POST']) @authorised_role(role=Role.WRITER) @login_required def update_todo(id): status = request.form.get('status') item = get_item(id) item.status = ItemStatus.COMPLETE if status == 'COMPLETE' else ItemStatus.NOT_STARTED save_item(item) return redirect('/') @app.route('/todos/<id>/delete', methods=['POST']) @authorised_role(role=Role.WRITER) @login_required def remove_todo(id): delete_item(id) return redirect('/') return app
def test_code_in_uri(self): """Tests whether the value of code is retained in the uri""" client = WebApplicationClient('*****@*****.**') uri = "https://gCallback/?state=dummy_state&code=dummy_code" self.assertTrue('dummy_code' in client.parse_request_uri_response(uri, state='dummy_state').values())
@login_manager.unauthorized_handler def unauthorized(): return "You must be logged in to access this content.", 403 # Naive database setup try: init_db_command() except sqlite3.OperationalError: # Assume it's already been created pass # OAuth2 client setup client = WebApplicationClient(GOOGLE_CLIENT_ID) # Flask-Login helper to retrieve a user from our db @login_manager.user_loader def load_user(user_id): return User.get(user_id) @app.route("/") def index(): if current_user.is_authenticated: return ("<p>Hello, {}! You're logged in! Email: {}</p>" "<div><p>Google Profile Picture:</p>" '<img src="{}" alt="Google profile pic"></img></div>' '<a class="button" href="/logout">Logout</a>'.format(
#Not sure why it's not in its own function @login_manager.unauthorized_handler def unauthorized(): return ('You must be logged in to access this content.', 403) # Naive database setup try: init_db_command() except sqlite3.OperationalError: # Assume it's already been created pass # OAuth 2 client setup client = WebApplicationClient(client_id) if (set_up) else WebApplicationClient( custom_id_getter(True)) # Don't want to needlessly open files ############################################ # Flask-Login helper to retrieve a user from our db @login_manager.user_loader def load_user(user_id): return User.get(user_id) def fix_location(l1): #fixes GPS coordinates as stored on DB l1 = l1.replace('D', ', ') return l1
# Creating the Flask app instance printColoured(" * Initialising Flask application") app = Flask(__name__) CORS(app) # ===== App Configuration ===== SECRET_KEY = os.getenv("SECRET_KEY") app.secret_key = SECRET_KEY GOOGLE_API_CLIENT_SECRET = os.getenv("GOOGLE_API_CLIENT_SECRET") GOOGLE_API_CLIENT_ID = os.getenv("GOOGLE_API_CLIENT_ID") GOOGLE_DISCOVERY_URL = ( "https://accounts.google.com/.well-known/openid-configuration") google_client = WebApplicationClient(GOOGLE_API_CLIENT_ID) # Registering the default error handler app.register_error_handler(Exception, error_handler) # Database connection parameters: client = pymongo.MongoClient( "mongodb+srv://teamgalactic:[email protected]/galacticed?retryWrites=true&w=majority" ) # Creating the database handler: db = client["galacticed"] # The routes must be imported after the Flask application object is created. See https://flask.palletsprojects.com/en/1.1.x/patterns/packages/ import GalacticEd.routes
from flask import Flask, render_template, url_for, flash, redirect, jsonify, request from FlaskApp import app, config from FlaskApp.forms import LoginForm from flask_login import current_user, logout_user,login_required from requests_oauthlib import OAuth2Session from oauthlib.oauth2 import WebApplicationClient import jwt, requests, json, datetime client = WebApplicationClient(config.GOOGLE_CLIENT_ID) @app.route("/about") def about(): return render_template('about.html', title='About') @app.route("/", methods=['GET', 'POST']) @app.route("/login_home", methods=['GET', 'POST']) def login_home(): form = LoginForm() if form.validate_on_submit(): if form.email.data == '*****@*****.**' and form.password.data == 'password': token = jwt.encode({'user' : form.email.data, 'exp' : datetime.datetime.utcnow() + datetime.timedelta(seconds = 30)},app.config['SECRET_KEY']) return jsonify({'token' : token.decode('UTF-8')}) else: flash('Login Unsuccessful. Please check username and password', 'danger') return render_template('login.html', title='Login', form=form)
# User session management setup # https://flask-login.readthedocs.io/en/latest login_manager = LoginManager() login_manager.init_app(app) # Naive database setup try: init_db_command() except sqlite3.OperationalError: # Assume it's already been created pass # OAuth 2 client setup client = WebApplicationClient(WS1_CLIENT_ID) def get_ws1_provider_cfg(): return requests.get(WS1_DISCOVERY_URL).json() # Flask-Login helper to retrieve a user from our db @login_manager.unauthorized_handler def unauthorized(): # do stuff return redirect(url_for('login')) @login_manager.user_loader def load_user(user_id): return User.get(user_id)
def get_client(): client = WebApplicationClient(mg_config['client_id']) return client
def get(self, request, *args, **kwargs): # Retrieve these data from the URL data = self.request.GET code = data['code'] state = data['state'] print("code=%s, state=%s" % (code, state)) # For security purposes, verify that the # state information is the same as was passed # to github_login() if self.request.session['state'] != state: messages.add_message(self.request, messages.ERROR, "State information mismatch!") return HttpResponseRedirect(reverse('github:welcome')) else: del self.request.session['state'] # fetch the access token from GitHub's API at token_url token_url = 'https://github.com/login/oauth/access_token' client_id = settings.GITHUB_OAUTH_CLIENT_ID client_secret = settings.GITHUB_OAUTH_SECRET # Create a Web Applicantion Client from oauthlib client = WebApplicationClient(client_id) # Prepare body for request data = client.prepare_request_body( code=code, redirect_uri=settings.GITHUB_OAUTH_CALLBACK_URL, client_id=client_id, client_secret=client_secret) # Post a request at GitHub's token_url # Returns requests.Response object response = requests.post(token_url, data=data) """ Parse the unicode content of the response object Returns a dictionary stored in client.token { 'access_token': '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', 'scope': ['read:user'], 'token_type': 'bearer' } """ client.parse_request_body_response(response.text) # Prepare an Authorization header for GET request using the 'access_token' value # using GitHub's official API format header = { 'Authorization': 'token {}'.format(client.token['access_token']) } # Retrieve GitHub profile data # Send a GET request # Returns requests.Response object response = requests.get('https://api.github.com/user', headers=header) # Store profile data in JSON json_dict = response.json() ''' Fields that are of interest: 'login' => json_dict['login'], 'name' => json_dict['name'], 'bio' => json_dict['bio'], 'blog' => json_dict['blog'], 'email' => json_dict['email'], # not public data 'avatar_url' => json_dict['avatar_url'], ''' # save the user profile in a session self.request.session['profile'] = json_dict # retrieve or create a Django User for this profile try: user = User.objects.get(username=json_dict['login']) messages.add_message( self.request, messages.DEBUG, "User %s already exists, Authenticated? %s" % (user.username, user.is_authenticated)) print("User %s already exists, Authenticated %s" % (user.username, user.is_authenticated)) # remember to log the user into the system login(self.request, user) except: # create a Django User for this login user = User.objects.create_user(json_dict['login'], json_dict['email']) messages.add_message( self.request, messages.DEBUG, "User %s is created, Authenticated %s?" % (user.username, user.is_authenticated)) print("User %s is created, Authenticated %s" % (user.username, user.is_authenticated)) # remember to log the user into the system login(self.request, user) # Redirect response to hide the callback url in browser return HttpResponseRedirect(reverse('github:welcome'))
def api_auth_callback(self): s = self._settings d = settings_defaults() code = flask.request.args.get("code") token_endpoint = s.get(['token_endpoint']) client_id = s.get(['client_id']) client_secret = s.get(['client_secret']) userinfo_endpoint = s.get(['userinfo_endpoint']) orguser_endpoint = s.get(['orguser_endpoint']) organization = s.get(['organization']) username_key = s.get(['username_key']) self._logger.info('token_endpoint: ' + str(token_endpoint)) client = WebApplicationClient(client_id) token_url, headers, body = client.prepare_token_request( token_endpoint, # authorization_response=flask.request.url, # redirect_url=flask.request.base_url, code=code ) headers['Accept'] = 'application/json' token_response = requests.post( token_url, headers=headers, data=body, auth=(client_id, client_secret), ) client.parse_request_body_response(json.dumps(token_response.json())) uri, headers, body = client.add_token(userinfo_endpoint) headers['Accept'] = 'application/json' userinfo_response = requests.get(uri, headers=headers, data=body) userinfo = userinfo_response.json() username = userinfo[username_key] uri, headers, body = client.add_token(orguser_endpoint.format(organization, username)) headers['Accept'] = 'application/json' orguser_response = requests.get(uri, headers=headers, data=body) if orguser_response.status_code == 204: # User is part of the specified organization, find user or create it if it doesn't exist user = self._user_manager.login_user(OAuth2PGCUser(username)) flask.session["usersession.id"] = user.session flask.g.user = user self._logger.info("authenticated: " + str(user.is_authenticated)) self._logger.info("user: "******"Actively logging in user {} from {}".format(user.get_id(), remote_addr)) r = flask.redirect('/') r.delete_cookie("active_logout") eventManager().fire(Events.USER_LOGGED_IN, payload=dict(username=user.get_id())) return r return flask.redirect('/?error=unauthorized')
from todo_app.trello_api_calls import fetch_all_cards, change_card_status, \ TrelloCard from todo_app.view_model import ViewModel from todo_app.Authenticated_User import Authenticated_User import os from loggly.handlers import HTTPSHandler from logging import Formatter from flask_login import LoginManager, login_required, login_user, current_user from oauthlib.oauth2 import WebApplicationClient login_manager = LoginManager() oauth_client_id = os.environ.get('OAUTH_CLIENT_ID') oauth_client = WebApplicationClient(oauth_client_id) oauth_client_secret = os.environ.get('OAUTH_CLIENT_SECRET') def create_app(): app = Flask(__name__) app.config.from_object(Config) app.logger.setLevel(os.environ.get("LOG_LEVEL")) if os.environ.get("LOGGLY_TOKEN") is not None: args = "https://logs-01.loggly.com/inputs/" + os.environ.get( "LOGGLY_TOKEN") + "/tag/todo-app" handler = HTTPSHandler(args) handler.setFormatter( Formatter(
def test_prepare_request_body(self): """ see issue #585 https://github.com/oauthlib/oauthlib/issues/585 `prepare_request_body` should support the following scenarios: 1. Include client_id alone in the body (default) 2. Include client_id and client_secret in auth and not include them in the body (RFC preferred solution) 3. Include client_id and client_secret in the body (RFC alternative solution) 4. Include client_id in the body and an empty string for client_secret. """ client = WebApplicationClient(self.client_id) # scenario 1, default behavior to include `client_id` r1 = client.prepare_request_body() self.assertEqual(r1, 'grant_type=authorization_code&client_id=%s' % self.client_id) r1b = client.prepare_request_body(include_client_id=True) self.assertEqual(r1b, 'grant_type=authorization_code&client_id=%s' % self.client_id) # scenario 2, do not include `client_id` in the body, so it can be sent in auth. r2 = client.prepare_request_body(include_client_id=False) self.assertEqual(r2, 'grant_type=authorization_code') # scenario 3, Include client_id and client_secret in the body (RFC alternative solution) # the order of kwargs being appended is not guaranteed. for brevity, check the 2 permutations instead of sorting r3 = client.prepare_request_body(client_secret=self.client_secret) r3_params = dict(urlparse.parse_qsl(r3, keep_blank_values=True)) self.assertEqual(len(r3_params.keys()), 3) self.assertEqual(r3_params['grant_type'], 'authorization_code') self.assertEqual(r3_params['client_id'], self.client_id) self.assertEqual(r3_params['client_secret'], self.client_secret) r3b = client.prepare_request_body(include_client_id=True, client_secret=self.client_secret) r3b_params = dict(urlparse.parse_qsl(r3b, keep_blank_values=True)) self.assertEqual(len(r3b_params.keys()), 3) self.assertEqual(r3b_params['grant_type'], 'authorization_code') self.assertEqual(r3b_params['client_id'], self.client_id) self.assertEqual(r3b_params['client_secret'], self.client_secret) # scenario 4, `client_secret` is an empty string r4 = client.prepare_request_body(include_client_id=True, client_secret='') r4_params = dict(urlparse.parse_qsl(r4, keep_blank_values=True)) self.assertEqual(len(r4_params.keys()), 3) self.assertEqual(r4_params['grant_type'], 'authorization_code') self.assertEqual(r4_params['client_id'], self.client_id) self.assertEqual(r4_params['client_secret'], '') # scenario 4b, `client_secret` is `None` r4b = client.prepare_request_body(include_client_id=True, client_secret=None) r4b_params = dict(urlparse.parse_qsl(r4b, keep_blank_values=True)) self.assertEqual(len(r4b_params.keys()), 2) self.assertEqual(r4b_params['grant_type'], 'authorization_code') self.assertEqual(r4b_params['client_id'], self.client_id) # scenario Warnings with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") # catch all # warning1 - raise a DeprecationWarning if a `client_id` is submitted rWarnings1 = client.prepare_request_body(client_id=self.client_id) self.assertEqual(len(w), 1) self.assertIsInstance(w[0].message, DeprecationWarning) # testing the exact warning message in Python2&Python3 is a pain # scenario Exceptions # exception1 - raise a ValueError if the a different `client_id` is submitted with self.assertRaises(ValueError) as cm: client.prepare_request_body(client_id='different_client_id')
def unauthenticated(): client = WebApplicationClient(os.getenv("CLIENT_ID")) client.state = client.state_generator() authredirect = client.prepare_request_uri( "https://github.com/login/oauth/authorize", state=client.state) return redirect(authredirect)
class OAuthClient: """ Helper class to handle the OAuth authentication flow the logic is divided in 2 steps: - open the browser on GitGuardian login screen and run a local server to wait for callback - handle the oauth callback to exchange an authorization code against a valid access token """ def __init__(self, config: Config, instance: str) -> None: self.config = config self.instance = instance self._oauth_client = WebApplicationClient(CLIENT_ID) self._state = "" # use the `state` property instead self._handler_wrapper = RequestHandlerWrapper(oauth_client=self) self._access_token: Optional[str] = None self._port = USABLE_PORT_RANGE[0] self.server: Optional[HTTPServer] = None self._generate_pkce_pair() def oauth_process(self, token_name: Optional[str] = None, lifetime: Optional[int] = None) -> None: """ Handle the whole oauth process which includes - opening the user's webbrowser to GitGuardian login page - open a server and wait for the callback processing """ # enable redirection to http://localhost os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = str(True) if token_name is None: token_name = "ggshield token " + datetime.today().strftime( "%Y-%m-%d") self._token_name = token_name if lifetime is None: lifetime = self.default_token_lifetime self._lifetime = lifetime self._prepare_server() self._redirect_to_login() self._wait_for_callback() message = f"Created Personal Access Token {self._token_name} " expire_at = self.instance_config.account.expire_at if expire_at is not None: message += "expiring on " + get_pretty_date(expire_at) else: message += "with no expiry" click.echo(message) def process_callback(self, callback_url: str) -> None: """ This function runs within the request handler do_GET method. It takes the url of the callback request as argument and does - Extract the authorization code - Exchange the code against an access token with GitGuardian's api - Validate the new token against GitGuardian's api - Save the token in configuration Any error during this process will raise a OAuthError """ authorization_code = self._get_code(callback_url) self._claim_token(authorization_code) token_data = self._validate_access_token() self._save_token(token_data) def _generate_pkce_pair(self) -> None: """ Generate a code verifier (random string) and its sha encoded version to be used for the pkce checking process """ self.code_verifier = self._oauth_client.create_code_verifier( 128) # type: ignore self.code_challenge = (urlsafe_b64encode( sha256(self.code_verifier.encode()).digest()).decode().rstrip("=")) def _redirect_to_login(self) -> None: """ Open the user's browser to the GitGuardian ggshield authentication page """ static_params = { "auth_mode": "ggshield_login", "utm_source": "cli", "utm_medium": "login", "utm_campaign": "ggshield", } request_uri = self._oauth_client.prepare_request_uri( uri=urlparse.urljoin(self.dashboard_url, "auth/login"), redirect_uri=self.redirect_uri, scope=SCOPE, code_challenge=self.code_challenge, code_challenge_method="S256", state=self.state, **static_params, ) click.echo( f"To complete the login process, follow the instructions from {request_uri}.\n" "Opening your web browser now...") webbrowser.open_new_tab(request_uri) def _prepare_server(self) -> None: for port in range(*USABLE_PORT_RANGE): try: self.server = HTTPServer( # only consider requests from localhost on the predetermined port ("127.0.0.1", port), # attach the wrapped request handler self._handler_wrapper.request_handler, ) self._port = port break except OSError: continue else: raise click.ClickException("Could not find unoccupied port.") def _wait_for_callback(self) -> None: """ Wait to receive and process the authorization callback on the local server. This actually catches HTTP requests made on the previously opened server. The callback processing logic is implementend in the request handler class and the `process_callback` method """ try: while not self._handler_wrapper.complete: # Wait for callback on localserver including an authorization code # any matchin request will get processed by the request handler and # the `process_callback` function self.server.handle_request() # type: ignore except KeyboardInterrupt: raise click.ClickException("Aborting") if self._handler_wrapper.error_message is not None: # if no error message is attached, the process is considered successful raise click.ClickException(self._handler_wrapper.error_message) def _get_code(self, uri: str) -> str: """ Extract the authorization from the incoming request uri and verify that the state from the uri match the one stored internally. if no code can be extracted or the state is invalid, raise an OAuthError else return the extracted code """ try: authorization_code = self._oauth_client.parse_request_uri_response( uri, self.state).get("code") except OAuth2Error: authorization_code = None if authorization_code is None: raise OAuthError( "Invalid code or state received from the callback.") return authorization_code # type: ignore def _claim_token(self, authorization_code: str) -> None: """ Exchange the authorization code with a valid access token using GitGuardian public api. If no valid token could be retrieved, exit the authentication process with an error message """ request_params = {"name": self._token_name} if self._lifetime is not None: request_params["lifetime"] = str(self._lifetime) request_body = self._oauth_client.prepare_request_body( code=authorization_code, redirect_uri=self.redirect_uri, code_verifier=self.code_verifier, body=urlparse.urlencode(request_params), ) response = requests.post( urlparse.urljoin(self.api_url, "oauth/token"), request_body, headers={"Content-Type": "application/x-www-form-urlencoded"}, ) if not response.ok: raise OAuthError("Cannot create a token.") self._access_token = response.json()["key"] self.config.auth_config.current_token = self._access_token def _validate_access_token(self) -> Dict[str, Any]: """ Validate the token using GitGuardian public api. If the token is not valid, exit the authentication process with an error message. """ response = retrieve_client(self.config).get(endpoint="token") if not response.ok: raise OAuthError("The created token is invalid.") return response.json() # type: ignore def _save_token(self, api_token_data: Dict[str, Any]) -> None: """ Save the new token in the configuration. """ account_config = AccountConfig( account_id=api_token_data["account_id"], token=self._access_token, # type: ignore expire_at=api_token_data.get("expire_at"), token_name=api_token_data.get("name", ""), type=api_token_data.get("type", ""), ) self.instance_config.account = account_config self.config.save() @property def instance_config(self) -> InstanceConfig: return self.config.auth_config.instances[self.instance] @property def default_token_lifetime(self) -> Optional[int]: """ return the default token lifetime saved in the instance config. if None, this will be interpreted as no expiry. """ default_lifetime = self.instance_config.default_token_lifetime if default_lifetime is not None: return default_lifetime.days return None @property def redirect_uri(self) -> str: return f"http://localhost:{self._port}" @property def state(self) -> str: """ Return the state used to verify the auth process. The state is included in the redirect_uri and is expected in the callback url. Then, if both states don't match, the process fails. The state is an url-encoded string dict containing the token name and lifetime It is cached to prevent from altering its value during the process """ if not self._state: self._state = urlparse.quote( json.dumps({ "token_name": self._token_name, "lifetime": self._lifetime })) return self._state @property def dashboard_url(self) -> str: return self.config.dashboard_url @property def api_url(self) -> str: return self.config.api_url
def create_app(): # Defining logger logger = logging.getLogger(__name__) logger.warning('Hello, World!') logging.basicConfig(level=os.getenv('LOG_LEVEL', 'INFO')) # Launch app app = Flask(__name__) app.config.from_object(Config()) # Loggly if app.config['LOGGLY_TOKEN'] is not None: handler = HTTPSHandler(f'https://logs-01.loggly.com/inputs/{app.config["LOGGLY_TOKEN"]}/tag/todo-app') handler.setFormatter( jsonlogger.JsonFormatter("[%(asctime)s] %(levelname)s in %(module)s: %(message)s") ) app.logger.addHandler(handler) getLogger('werkzeug').addHandler(HTTPSHandler(f'https://logs-01.loggly.com/inputs/{app.config["LOGGLY_TOKEN"]}/tag/todoapp-requests')) # Connect to mongo si.connect_mongo() # All the routes and setup code etc # Index @app.route('/') @reader_required def index(): items = si.get_items() item_view_model = ViewModel(items) return render_template('index.html', view_model = item_view_model) # Add item @app.route('/create_item', methods = ['POST']) @writer_required def create_item(): title = request.form ['title'] si.add_item(title) return redirect(url_for('index')) # Update item status @app.route('/item_status', methods = ['GET','POST']) @writer_required def item_status(): item_title = request.form ['item_title'] item_status = request.form ['item_status'] item = si.get_item(item_title) if item != None: si.save_item(item,item_status) return redirect(url_for('index')) # Delete item @app.route('/del_item', methods = ['GET','POST']) @writer_required def del_item(): del_title = request.form['del_title'] delete_item(del_title) logger.info("Item deleted: %s", del_title) return redirect(url_for('index')) # Route for logout @app.route('/logout') @login_required def logout(): logger.info("User logged out. User id: %s", current_user.id) logout_user() return redirect(url_for('index')) ### OAuth ### # Obtain GitHub OAuth Secrets: client_id = os.getenv('CLIENT_ID') client_secret = os.getenv('CLIENT_SECRET') # Initialize login_manager class login_manager = flask_login.LoginManager() # Create client client = WebApplicationClient(client_id) @login_manager.unauthorized_handler def unauthenticated(): # Add logic to redirect to the Github OAuth flow when unauthenticated # Request identity # Redirect to site # Return -> redirect to github redirecturl = client.prepare_request_uri("https://github.com/login/oauth/authorize") return redirect(redirecturl) @login_manager.user_loader def load_user(user_id): return User(user_id) @app.route('/login', methods = ['GET']) def login(): code = request.args.get('code') token_url, headers, body = client.prepare_token_request('https://github.com/login/oauth/access_token', code = code ) headers['Accept']= 'application/json' response = requests.post(token_url, headers = headers, data = body, auth = (client_id,client_secret)) response = response.json() access_token = response['access_token'] usr_url = 'https://api.github.com/user' headers = {'Authorization': 'token ' + access_token} usr_response = requests.get(usr_url, headers = headers ) usr_response = usr_response.json() user = User(usr_response['id']) login_user(user) logger.info("User logged in: %s", usr_response['id']) return redirect(url_for('index')) login_manager.init_app(app) ### MAIN ### if __name__ == '__main__': app.run() return app
def create_oauth2_session(self): if self.auth_type != OAUTH2: raise ValueError( 'Auth type must be %r for credentials type OAuth2Credentials' % OAUTH2) has_token = False scope = ['https://outlook.office365.com/.default'] session_params = {} token_params = {} if isinstance(self.credentials, OAuth2AuthorizationCodeCredentials): # Ask for a refresh token scope.append('offline_access') # We don't know (or need) the Microsoft tenant ID. Use # common/ to let Microsoft select the appropriate tenant # for the provided authorization code or refresh token. # # Suppress looks-like-password warning from Bandit. token_url = 'https://login.microsoftonline.com/common/oauth2/v2.0/token' # nosec client_params = {} has_token = self.credentials.access_token is not None if has_token: session_params['token'] = self.credentials.access_token elif self.credentials.authorization_code is not None: token_params['code'] = self.credentials.authorization_code self.credentials.authorization_code = None if self.credentials.client_id is not None and self.credentials.client_secret is not None: # If we're given a client ID and secret, we have enough # to refresh access tokens ourselves. In other cases the # session will raise TokenExpiredError and we'll need to # ask the calling application to refresh the token (that # covers cases where the caller doesn't have access to # the client secret but is working with a service that # can provide it refreshed tokens on a limited basis). session_params.update({ 'auto_refresh_kwargs': { 'client_id': self.credentials.client_id, 'client_secret': self.credentials.client_secret, }, 'auto_refresh_url': token_url, 'token_updater': self.credentials.on_token_auto_refreshed, }) client = WebApplicationClient(self.credentials.client_id, **client_params) else: token_url = 'https://login.microsoftonline.com/%s/oauth2/v2.0/token' % self.credentials.tenant_id client = BackendApplicationClient( client_id=self.credentials.client_id) session = self.raw_session(client, session_params) if not has_token: # Fetch the token explicitly -- it doesn't occur implicitly token = session.fetch_token( token_url=token_url, client_id=self.credentials.client_id, client_secret=self.credentials.client_secret, scope=scope, **token_params) # Allow the credentials object to update its copy of the new # token, and give the application an opportunity to cache it self.credentials.on_token_auto_refreshed(token) session.auth = get_auth_instance(auth_type=OAUTH2, client=client) return session
def create_app(): app = Flask(__name__) app.config.from_object('todo_app.flask_config.Config') app.logger.setLevel(app.config['LOG_LEVEL']) app.wsgi_app = ReverseProxied(app.wsgi_app) if app.config['LOGGLY_TOKEN'] is not None: handler = HTTPSHandler(f'https://logs-01.loggly.com/inputs/{app.config["LOGGLY_TOKEN"]}/tag/todo-app') formatter = jsonlogger.JsonFormatter("[%(asctime)s] %(levelname)s in %(module)s: %(message)s %(requesterIpAddr)s") handler.setFormatter(formatter) app.logger.addHandler(handler) client_id = os.environ['GITHUB_CLIENT_ID'] client_secret = os.environ['GITHUB_CLIENT_SECRET'] base_url="https://api.github.com" authorization_url="https://github.com/login/oauth/authorize" token_endpoint = "https://github.com/login/oauth/access_token" client = WebApplicationClient(client_id) todo = mongodb_todo() usermanager = MongoDbUserService() login_manager = LoginManager() login_manager.init_app(app) @app.errorhandler(Exception) def handle_error(e): app.logger.error('exception', extra={ "method": "{}".format(request.method), "requesterIpAddr": "{}".format(request.remote_addr), "url": "{}".format(request.url) }, exc_info=True) return render_template("error.html", error=str(e)) @app.after_request def after_request(response): app.logger.info("after_request", extra={ "method": "{}".format(request.method), "requesterIpAddr": "{}".format(request.remote_addr), "url": "{}".format(request.url), "status_code": "{}".format(response.status) }) return response @login_manager.user_loader def load_user(user_id): return UserToLogin(user_id) @login_manager.unauthorized_handler def unauthenticated(): app.logger.info("Unauthorized attemp made.", extra={ "method": "{}".format(request.method), "requesterIpAddr": "{}".format(request.remote_addr), "url": "{}".format(request.url) }) return redirect(url_for('login')) @app.route('/logout') @login_required def logout(): app.logger.info("User {} logged out of the system.".format(current_user.id), extra={ "method": "{}".format(request.method), "requesterIpAddr": "{}".format(request.remote_addr), "url": "{}".format(request.url) }) logout_user() session.clear() return redirect("https://github.com/logout") @app.route("/login") def login(): request_uri = client.prepare_request_uri( authorization_url, redirect_uri=request.base_url + "/callback", scope=None, ) return redirect(request_uri) @app.route("/login/callback") def callback(): code = request.args.get("code") app.logger.debug("{}".format(code), extra={ "method": "{}".format(request.method), "requesterIpAddr": "{}".format(request.remote_addr), "url": "{}".format(request.url) }) # Prepare and send request to get tokens! token_url, headers, body = client.prepare_token_request( token_endpoint, authorization_response=request.url, redirect_url=request.base_url, code=code, ) token_response = requests.post( token_url, headers=headers, data=body, auth=(client_id, client_secret), ) if token_response.status_code != 200: return redirect(url_for('login')) json_data = token_response.content.decode('utf8').replace("'", '"') # Parse the tokens! client.parse_request_body_response(json_data) userinfo_endpoint = "{}/user".format(base_url) uri, headers, body = client.add_token(userinfo_endpoint) userinfo_response = requests.get(uri, headers=headers, data=body) if userinfo_response.ok: account_info_json = userinfo_response.json() currentUserName = str(account_info_json['login']) login_user(UserToLogin(currentUserName)) app.logger.info("User logged in {}".format(current_user.id), extra={ "method": "{}".format(request.method), "requesterIpAddr": "{}".format(request.remote_addr), "url": "{}".format(request.url) }) if usermanager.get_totalusercount() == 0: usermanager.create_user(username=currentUserName,role="admin") app.logger.info("User logged in {} has been give admin level access.".format(current_user.id), extra={ "method": "{}".format(request.method), "requesterIpAddr": "{}".format(request.remote_addr), "url": "{}".format(request.url) }) if (usermanager.get_totalusercount() > 0) and (usermanager.get_findusercount(qry={"username": currentUserName}) == 0): usermanager.create_user(username=currentUserName,role="read") app.logger.info("User logged in {} has been give read level access.".format(current_user.id), extra={ "method": "{}".format(request.method), "requesterIpAddr": "{}".format(request.remote_addr), "url": "{}".format(request.url) }) return redirect(url_for('get_index')) @app.route('/', methods=['GET']) @login_required def sendhome(): return redirect(url_for('get_index')) ##### Core TODO_Tasks##### #error handling for 404 # @app.errorhandler(404) # def not_found(e): # return render_template("error.html", error='resource not found!') @app.route('/contact') def contact(): return render_template('contact.html') @app.route('/home', methods=['GET']) @login_required def get_index(): cardslist = [] items = todo.get_AllItems() if (app.config['LOGIN_DISABLED']): userRole = False else: userRole = usermanager.IsDisable() for item in items: cardslist.append(Card(item)) item_view_model = ViewModel(cardslist) return render_template('index.html', view_model=item_view_model, strRole=userRole) @app.route('/new', methods=['GET']) # New Task @login_required @usermanager.hasWritePermission def getnew_post(): return render_template('new_task.html') @app.route('/home', methods=['POST']) # New Task @login_required @usermanager.hasWritePermission def post_index(): response = todo.create_task( name = request.form['title'], due = request.form['duedate'], desc = request.form['descarea'] ) if response is not None: if current_app.config["LOGIN_DISABLED"]==False: app.logger.info("{} create new task".format(current_user.id), extra={ "method": "{}".format(request.method), "requesterIpAddr": "{}".format(request.remote_addr), "url": "{}".format(request.url), "data": "name: {} due: {} desc: {}".format(request.form['title'], str(request.form['duedate']), request.form['descarea']) }) return redirect('/home') else: return render_template("error.html",error="failed to create task!") @app.route('/edit/<id>', methods=['GET']) #Edit task @login_required @usermanager.hasWritePermission def get_edit(id): item = todo.get_task(id=id) if item is not None: item_info = Card(item) return render_template('edit.html', task=item_info) else: return render_template("error.html", error="failed to obtain task info!") @app.route('/edit/<id>', methods=['POST']) #Edit task @login_required @usermanager.hasWritePermission def post_edit(id): response= todo.update_task( id = id, name = request.form['title'], desc = request.form['descarea'], due = request.form['duedate'], status = request.form['status'] ) if response is not None: if current_app.config["LOGIN_DISABLED"]==False: app.logger.info("{} update task".format(current_user.id), extra={ "method": "{}".format(request.method), "requesterIpAddr": "{}".format(request.remote_addr), "url": "{}".format(request.url), "data": "id: {} name: {} due: {} desc: {} status: {}".format(id, request.form['title'], str(request.form['duedate']), request.form['descarea'], request.form['status']) }) return redirect('/home') else: return render_template("error.html", error="failed to update task!") @app.route('/delete/<id>') # delete task @login_required @usermanager.hasWritePermission def delete(id): response = todo.delete_task(id=id) if response is not None: if current_app.config["LOGIN_DISABLED"]==False: app.logger.info("{} deleted task".format(current_user.id), extra={ "method": "{}".format(request.method), "requesterIpAddr": "{}".format(request.remote_addr), "url": "{}".format(request.url), "data": "id: {}".format(id) }) return redirect('/home') else: return render_template("error.html",error="failed to delete task!") ### Additional views ### @app.route('/getpreviousdonetasks', methods=['GET']) @login_required def get_previous_done_tasks(): cardslist = [] items = todo.get_older_done_task() for item in items: cardslist.append(Card(item)) item_view_model = ViewModel(cardslist) userRole = usermanager.IsDisable() return render_template('previous_done_task.html', view_model=item_view_model, strRole=userRole) @app.route('/gettodaydonetasks', methods=['GET']) @login_required def get_today_done_tasks(): cardslist = [] items = todo.get_today_done_task() for item in items: cardslist.append(Card(item)) item_view_model = ViewModel(cardslist) userRole = usermanager.IsDisable() return render_template('today_done_task.html', view_model=item_view_model, strRole=userRole) ############# UserManagement ########################## @app.route('/usermanager', methods=['GET']) #portal @login_required @usermanager.hasRoleAdmin def get_usermanager(): user_list = [] items = usermanager.get_AllUsers() for item in items: user_list.append(User(item)) item_view_model = ViewModel(user_list) return render_template('userManager.html', view_model=item_view_model) @app.route('/edituser/<id>', methods=['GET']) #Edit user @login_required @usermanager.hasRoleAdmin def get_edituser(id): item = usermanager.get_user(id=id) if item is not None: item_info = User(item) return render_template('editUser.html', user=item_info) else: return render_template("error.html", error="failed to obtain user info!") @app.route('/edituser/<id>', methods=['POST']) #Edit user @login_required @usermanager.hasRoleAdmin def post_edituser(id): response = usermanager.update_user( id = id, username = request.form['username'], role = request.form['role'] ) if response is not None: app.logger.info("{} updated user permission".format(current_user.id), extra={ "method": "{}".format(request.method), "requesterIpAddr": "{}".format(request.remote_addr), "url": "{}".format(request.url), "data": "id: {} username: {} role: {}".format(id, request.form['username'], request.form['role']) }) return redirect('/usermanager') else: return render_template("error.html", error="failed to update user!") @app.route('/deleteuser/<id>') # delete user @login_required @usermanager.hasRoleAdmin def deleteuser(id): response = usermanager.delete_user(id=id) if response is not None: app.logger.info("{} deleted user".format(current_user.id), extra={ "method": "{}".format(request.method), "requesterIpAddr": "{}".format(request.remote_addr), "url": "{}".format(request.url), "data": "id: {}".format(id) }) return redirect('/usermanager') else: return render_template("error.html",error="failed to delete user!") ############################################### return app
def do_run(config, endpoint_list): #setup some globals server_uri = config.get("server_uri") global SPLUNK_PORT global STANZA global SESSION_TOKEN global delimiter SPLUNK_PORT = server_uri[18:] STANZA = config.get("name") SESSION_TOKEN = config.get("session_key") #params http_method = config.get("http_method", "GET") request_payload = config.get("request_payload") #none | basic | digest | oauth1 | oauth2 auth_type = config.get("auth_type", "none") #Delimiter to use for any multi "key=value" field inputs delimiter = config.get("delimiter", ",") #for basic and digest auth_user = config.get("auth_user") auth_password = config.get("auth_password") #for oauth1 oauth1_client_key = config.get("oauth1_client_key") oauth1_client_secret = config.get("oauth1_client_secret") oauth1_access_token = config.get("oauth1_access_token") oauth1_access_token_secret = config.get("oauth1_access_token_secret") #for oauth2 oauth2_token_type = config.get("oauth2_token_type", "Bearer") oauth2_access_token = config.get("oauth2_access_token") oauth2_refresh_token = config.get("oauth2_refresh_token") oauth2_refresh_url = config.get("oauth2_refresh_url") oauth2_refresh_props_str = config.get("oauth2_refresh_props") oauth2_client_id = config.get("oauth2_client_id") oauth2_client_secret = config.get("oauth2_client_secret") oauth2_refresh_props = {} if not oauth2_refresh_props_str is None: oauth2_refresh_props = dict((k.strip(), v.strip()) for k, v in ( item.split('=', 1) for item in oauth2_refresh_props_str.split(delimiter))) oauth2_refresh_props['client_id'] = oauth2_client_id oauth2_refresh_props['client_secret'] = oauth2_client_secret http_header_propertys = {} http_header_propertys_str = config.get("http_header_propertys") if not http_header_propertys_str is None: http_header_propertys = dict((k.strip(), v.strip()) for k, v in ( item.split('=', 1) for item in http_header_propertys_str.split(delimiter))) url_args = {} url_args_str = config.get("url_args") if not url_args_str is None: url_args = dict( (k.strip(), v.strip()) for k, v in (item.split('=', 1) for item in url_args_str.split(delimiter))) #json | xml | text response_type = config.get("response_type", "text") streaming_request = int(config.get("streaming_request", 0)) http_proxy = config.get("http_proxy") https_proxy = config.get("https_proxy") proxies = {} if not http_proxy is None: proxies["http"] = http_proxy if not https_proxy is None: proxies["https"] = https_proxy cookies = {} cookies_str = config.get("cookies") if not cookies_str is None: cookies = dict((k.strip(), v.strip()) for k, v in (item.split('=', 1) for item in cookies_str.split(delimiter))) request_timeout = int(config.get("request_timeout", 30)) backoff_time = int(config.get("backoff_time", 10)) sequential_stagger_time = int(config.get("sequential_stagger_time", 0)) polling_interval_string = config.get("polling_interval", "60") if polling_interval_string.isdigit(): polling_type = 'interval' polling_interval = int(polling_interval_string) else: polling_type = 'cron' cron_start_date = datetime.now() cron_iter = croniter(polling_interval_string, cron_start_date) index_error_response_codes = int( config.get("index_error_response_codes", 0)) response_filter_pattern = config.get("response_filter_pattern") if response_filter_pattern: global REGEX_PATTERN REGEX_PATTERN = re.compile(response_filter_pattern) response_handler_args = {} response_handler_args_str = config.get("response_handler_args") if not response_handler_args_str is None: response_handler_args = dict((k.strip(), v.strip()) for k, v in ( item.split('=', 1) for item in response_handler_args_str.split(delimiter))) response_handler = config.get("response_handler", "DefaultResponseHandler") module = __import__("responsehandlers") class_ = getattr(module, response_handler) global RESPONSE_HANDLER_INSTANCE RESPONSE_HANDLER_INSTANCE = class_(**response_handler_args) custom_auth_handler = config.get("custom_auth_handler") if custom_auth_handler: module = __import__("authhandlers") class_ = getattr(module, custom_auth_handler) custom_auth_handler_args = {} custom_auth_handler_args_str = config.get("custom_auth_handler_args") if not custom_auth_handler_args_str is None: custom_auth_handler_args = dict( (k.strip(), v.strip()) for k, v in ( item.split('=', 1) for item in custom_auth_handler_args_str.split(delimiter))) CUSTOM_AUTH_HANDLER_INSTANCE = class_(**custom_auth_handler_args) try: auth = None oauth2 = None if auth_type == "basic": auth = HTTPBasicAuth(auth_user, auth_password) elif auth_type == "digest": auth = HTTPDigestAuth(auth_user, auth_password) elif auth_type == "oauth1": auth = OAuth1(oauth1_client_key, oauth1_client_secret, oauth1_access_token, oauth1_access_token_secret) elif auth_type == "oauth2": token = {} token["token_type"] = oauth2_token_type token["access_token"] = oauth2_access_token token["refresh_token"] = oauth2_refresh_token token["expires_in"] = "5" client = WebApplicationClient(oauth2_client_id) oauth2 = OAuth2Session(client, token=token, auto_refresh_url=oauth2_refresh_url, auto_refresh_kwargs=oauth2_refresh_props, token_updater=oauth2_token_updater) elif auth_type == "custom" and CUSTOM_AUTH_HANDLER_INSTANCE: auth = CUSTOM_AUTH_HANDLER_INSTANCE req_args = { "verify": False, "stream": bool(streaming_request), "timeout": float(request_timeout) } if auth: req_args["auth"] = auth if url_args: req_args["params"] = url_args if cookies: req_args["cookies"] = cookies if http_header_propertys: req_args["headers"] = http_header_propertys if proxies: req_args["proxies"] = proxies if request_payload and not http_method == "GET": req_args["data"] = request_payload while True: if polling_type == 'cron': next_cron_firing = cron_iter.get_next(datetime) while get_current_datetime_for_cron() != next_cron_firing: time.sleep(float(10)) for endpoint in endpoint_list: if "params" in req_args: req_args_params_current = dictParameterToStringFormat( req_args["params"]) else: req_args_params_current = "" if "cookies" in req_args: req_args_cookies_current = dictParameterToStringFormat( req_args["cookies"]) else: req_args_cookies_current = "" if "headers" in req_args: req_args_headers_current = dictParameterToStringFormat( req_args["headers"]) else: req_args_headers_current = "" if "data" in req_args: req_args_data_current = req_args["data"] else: req_args_data_current = "" try: if oauth2: if http_method == "GET": r = oauth2.get(endpoint, **req_args) elif http_method == "POST": r = oauth2.post(endpoint, **req_args) elif http_method == "PUT": r = oauth2.put(endpoint, **req_args) else: if http_method == "GET": r = requests.get(endpoint, **req_args) elif http_method == "POST": r = requests.post(endpoint, **req_args) elif http_method == "PUT": r = requests.put(endpoint, **req_args) except requests.exceptions.Timeout, e: logging.error("HTTP Request Timeout error: %s" % str(e)) time.sleep(float(backoff_time)) continue except Exception as e: logging.error("Exception performing request: %s" % str(e)) time.sleep(float(backoff_time)) continue try: r.raise_for_status() if streaming_request: for line in r.iter_lines(): if line: handle_output(r, line, response_type, req_args, endpoint) else: handle_output(r, r.text, response_type, req_args, endpoint) except requests.exceptions.HTTPError, e: error_output = r.text error_http_code = r.status_code if index_error_response_codes: error_event = "" error_event += 'http_error_code = %s error_message = %s' % ( error_http_code, error_output) print_xml_single_instance_mode(error_event) sys.stdout.flush() logging.error("HTTP Request error: %s" % str(e)) time.sleep(float(backoff_time)) continue
def create_app(): app = Flask(__name__) CLIENT_ID = os.environ.get("GITHUB_CLIENT_ID", None) CLIENT_SECRET = os.environ.get("GITHUB_CLIENT_SECRET", None) SECRET_KEY = os.environ.get("SECRET_KEY", None) WRITER_ROLE = os.environ.get("ROLEWRITER_USER", None) redirect_uri = os.environ.get("GITHUB_REDIRECT_URI", None) app.secret_key = SECRET_KEY logger = app.logger logger.setLevel(os.environ.get("LOG_LEVEL", "INFO")) if os.environ.get("LOGGLY_TOKEN", "") != "": handler = HTTPSHandler( f'https://logs-01.loggly.com/inputs/{os.environ.get("LOGGLY_TOKEN")}/tag/todo-app' ) handler.setFormatter( Formatter( "[%(asctime)s] %(levelname)s in %(module)s: %(message)s")) app.logger.addHandler(handler) client = WebApplicationClient(CLIENT_ID) login_manager = LoginManager() login_manager.init_app(app) logger.debug("Created Application") @login_manager.unauthorized_handler def unauthenticated(): identity_url = client.prepare_request_uri( 'https://github.com/login/oauth/authorize', redirect_uri) app.logger.debug("Github authentication") return redirect(identity_url) @app.route("/login/callback") def callback(): try: app.logger.debug("Github callback start") code = request.args.get("code") token_url, headers, body = client.prepare_token_request( "https://github.com/login/oauth/access_token", authorization_response=request.url, redirect_url=request.base_url, code=code, ) token_response = requests.post( token_url, headers=headers, data=body, auth=(CLIENT_ID, CLIENT_SECRET), ) # Parse the tokens! params = client.parse_request_body_response(token_response.text) uri, headers, body = client.add_token( "https://api.github.com/user") userinfo_response = requests.get(uri, headers=headers, data=body) app.logger.debug("Github callback succeess") users_name = userinfo_response.json()["login"] users_id = userinfo_response.json()["id"] email = userinfo_response.json()["email"] user = User(users_id, users_name, email, ROLES['reader']) appsession['users_id'] = users_id appsession['users_name'] = users_name appsession['email'] = email if users_name == WRITER_ROLE: user.access = ROLES['writer'] else: user.access = ROLES['reader'] app.logger.info("Logged in user %s", users_name) app.logger.info("Logged in user email %s", email) app.logger.info("Logged in user role %s", user.access) appsession['roles'] = user.access login_user(user) return redirect(url_for('index')) except Exception as e: app.logger.error(str(e)) return "Could not authenticate user." @login_manager.user_loader def load_user(user_id): app.logger.debug("Creating user object") m_user_id = appsession.get('users_id') m_users_name = appsession.get('users_name') m_users_roles = appsession.get('roles') m_email = appsession.get('email') user = User(m_user_id, m_users_name, m_email, m_users_roles) return user @app.route('/') @login_required @requires_roles('reader', 'writer') def index(): app.logger.debug("Index start") items = session.Boards().get_items() item_view_model = session.ViewModel(items) if app.config.get("LOGIN_DISABLED", False): mcurrent_user = '' misWriter = True #for E2E testing else: mcurrent_user = current_user.username misWriter = (appsession.get('roles') == ROLES['writer']) app.logger.info("Is Writer %s", misWriter) app.logger.debug("Index end") return render_template('index.html', view_model=item_view_model, isWriter=misWriter, currentuser=mcurrent_user) @app.route('/', methods=['POST']) @login_required @requires_roles('writer') def add_item(): title = request.form.get('title') app.logger.info("Add Item %s", title) if title != '': session.Boards().add_item(title) app.logger.info("Item Successfully Added by %s", current_user.id) return redirect('/') @app.route('/<id>') @login_required @requires_roles('writer') def complete_item(id): if (id != "favicon.ico"): app.logger.info("Complete Item %s", id) todo_class = session.Boards() item = todo_class.get_item(id) item['status'] = "Completed" todo_class.save_item(item) app.logger.info("Item %s successfully Completed", id) return redirect('/') @app.route('/todo/<id>') @login_required @requires_roles('writer') def uncomplete_item(id): if (id != "favicon.ico"): app.logger.info("UnComplete Item %s", id) todo_class = session.Boards() item = todo_class.get_item(id) item['status'] = "Not Started" todo_class.save_item(item) app.logger.info("Item %s Set to unomplete.", id) return redirect('/') @app.route('/doing/<id>') @login_required @requires_roles('writer') def start_item(id): if (id != "favicon.ico"): app.logger.info("Start Item %s", id) todo_class = session.Boards() item = todo_class.get_item(id) item['status'] = "Doing" todo_class.save_item(item) app.logger.info("Item %s successfully Started.", id) return redirect('/') @app.route('/remove/<id>') @login_required @requires_roles('writer') def delete_item(id): app.logger.info("Remove Item %s", id) todo_class = session.Boards() todo_class.remove_item(id) app.logger.info("Item %s successfully Removed.", id) return redirect('/') return app
REMEMBER_COOKIE_DURATION = datetime.timedelta(days=365), GOOGLE_CLIENT_ID = os.getenv("GOOGLE_CLIENT_ID"), GOOGLE_CLIENT_SECRET = os.getenv("GOOGLE_CLIENT_SECRET"), GOOGLE_DISCOVERY_URL = os.getenv("GOOGLE_DISCOVERY_URL"), IMAGEKIT_PRIVATE_KEY = os.getenv("IMAGEKIT_PRIVATE_KEY"), IMAGEKIT_PUBLIC_KEY = os.getenv("IMAGEKIT_PUBLIC_KEY"), IMAGEKIT_URL_ENDPOINT = os.getenv("IMAGEKIT_URL_ENDPOINT") ) # User session management setup # https://flask-login.readthedocs.io/en/latest login_manager = LoginManager() login_manager.init_app(app) # OAuth 2 client setup client = WebApplicationClient(app.config['GOOGLE_CLIENT_ID']) # enable CORS CORS(app, resources={r'/*': {'origins': '*'}}) @app.errorhandler(404) def not_found(error): return make_response(jsonify({'error': 'Not found'}), 404) @app.errorhandler(400) def bad_request(error): return make_response(jsonify({'error': 'Bad request'}), 400) @app.route("/") def index():
def vk_register(request): if request.user.is_authenticated(): return HttpResponseRedirect(reverse('user_detail')) code = request.GET.get('code', '') if code == '': raise ValueError(u"Bad response") #return render(request, 'tvevt/fail.html', context) client = WebApplicationClient(VK_APP_ID) uri = client.prepare_request_uri('https://oauth.vk.com/access_token', client_secret=VK_APP_SECRET, code=code, redirect_uri='http://localhost/vk_register') h = HTTPSConnection("vk.com") h.request('GET', uri) r = h.getresponse() body = r.read() r = json.loads(body) user_id = r["user_id"] access_token = r["access_token"] uri = client.prepare_request_uri('https://api.vk.com/method/users.get', user_id=user_id, access_token=access_token, fields='sex,bdate') h.request('GET', uri) r = h.getresponse() body = r.read() r = json.loads(body) user = r["response"][0] if user["uid"] <=0: raise ValueError(u"Bad uid value") list = User.objects.filter(vk_user_id=user["uid"]) if len(list) == 1: u = list[0] login(request, u) return HttpResponseRedirect(reverse('user_detail')) else: "Если пользователя нет, то регистрируем его" username = "******" % user["uid"] l = user["bdate"].split('.') year = int(l[2]) month = int(l[1]) day = int(l[0]) user["bdate"] = date(year, month, day) if user["sex"] == 2: user["sex"] = "male" elif user["sex"] == 1: user["sex"] = "female" else: user["sex"] == '' u = User(username=username, vk_user_id=user["uid"], first_name=user["first_name"], last_name=user["last_name"], gender=user["sex"], birth_date=user["bdate"]) u.save() login(request, u) return render(request, 'tvevt/success.html')
from contentagregator.config import google_config app = Flask(__name__) app.debug=True app.config.from_object('contentagregator.config.DevelopmentConfig') db = SQLAlchemy(app) assets = Environment(app) migrate = Migrate(app, db) api = Api(app) jwt = JWTManager(app) mail = Mail(app) seeder = FlaskSeeder(app, db) lang = Language(app) client = WebApplicationClient(google_config['google_client_id']) # celery setup def make_celery(app): celery = Celery(app.import_name, backend=app.config['CELERY_RESULT_BACKEND'], broker=app.config['CELERY_BROKER_URL']) celery.conf.update(app.config) TaskBase = celery.Task class ContextTask(TaskBase): abstract = True def __call__(self, *args, **kwargs): with app.app_context(): return TaskBase.__call__(self, *args, **kwargs) celery.Task = ContextTask return celery
def create_app(): mongo_db_client = pymongo.MongoClient( os.getenv('DATABASE_CONNECTION_STRING')) db = mongo_db_client[os.getenv('DATABASE_NAME')] collection = db['todo_app_items'] users_collection = db['users'] app = Flask(__name__) app.config.from_object('todo_app.flask_config.Config') app.secret_key = os.getenv('SECRET_KEY') login_manager = LoginManager() web_application_client = WebApplicationClient(os.getenv('CLIENT_ID')) class User(UserMixin): def __init__(self, id, name, user_role): self.id = id self.name = name self.user_role = user_role @login_manager.unauthorized_handler def unauthenticated(): return redirect( web_application_client.prepare_request_uri( 'https://github.com/login/oauth/authorize')) @login_manager.user_loader def load_user(user_id): query = {'github_id': user_id} db_user = users_collection.find_one(query) user = User(user_id, db_user['name'], db_user['user_role']) return user login_manager.init_app(app) @app.route('/login/callback', methods=['GET']) def login_user_callback(): token_url, headers, data = web_application_client.prepare_token_request( 'https://github.com/login/oauth/access_token', code=request.args['code'], client_id=os.getenv('CLIENT_ID'), client_secret=os.getenv('CLIENT_SECRET')) headers['Accept'] = 'application/json' response = requests.post(token_url, headers=headers, data=data) web_application_client.parse_request_body_response(response.text) access_token = web_application_client.token['access_token'] header = {'Authorization': f'Bearer {access_token}'} response = requests.get('https://api.github.com/user', headers=header).json() github_id = str(response['id']) query = {'github_id': github_id} db_user = users_collection.find_one(query) if (db_user) == None: if (users_collection.count_documents({}) == 0): user_role = 'admin' else: user_role = 'reader' post = { 'name': response['login'], 'github_id': github_id, 'user_role': user_role } users_collection.insert_one(post) db_user = users_collection.find_one(query) user = User(db_user['github_id'], db_user['name'], db_user['user_role']) login_user(user) return redirect('/') def is_writer(): return app.config[ 'LOGIN_DISABLED'] or current_user.user_role == 'writer' def is_admin(): return app.config['LOGIN_DISABLED'] or current_user.user_role == 'admin' @app.route('/') @login_required def index(): items = collection.find() cards = [] for item in items: cards.append( Item(item['_id'], item['name'], item['description'], item['due_date'].strftime('%d/%m/%Y'), item['status'])) item_view_model = ViewModel(cards) return render_template('index.html', view_model=item_view_model, is_writer=is_writer(), is_admin=is_admin()) @app.route('/create-todo/', methods=['POST']) def create_todo(): if not is_writer(): return redirect('/') title = request.form.get('title') desc = request.form.get('description') due = request.form.get('due-date') post = { 'name': title, 'description': desc, 'due_date': datetime.fromisoformat(due), 'status': todo_status } collection.insert_one(post) return redirect('/') @app.route('/todo/<id>', methods=['POST']) def to_do(id): if not is_writer(): return redirect('/') query = {'_id': ObjectId(id)} update_values = {'$set': {'status': todo_status}} collection.update_one(query, update_values) return redirect('/') @app.route('/doing/<id>', methods=['POST']) def doing(id): if not is_writer(): return redirect('/') query = {'_id': ObjectId(id)} update_values = {'$set': {'status': doing_status}} collection.update_one(query, update_values) return redirect('/') @app.route('/done/<id>', methods=['POST']) def done(id): if not is_writer(): return redirect('/') query = {'_id': ObjectId(id)} update_values = {'$set': {'status': done_status}} collection.update_one(query, update_values) return redirect('/') @app.route('/delete/<id>', methods=['POST']) def delete(id): if not is_writer(): return redirect('/') query = {'_id': ObjectId(id)} collection.delete_one(query) return redirect('/') @app.route('/users', methods=['GET']) def users(): db_users = users_collection.find() users = [] for item in db_users: user = User(item['github_id'], item['name'], item['user_role']) users.append(user) return render_template('users.html', users=users) @app.route('/update-user-role/<id>/<user_role>', methods=['POST']) def update_user_role(id, user_role): if not is_admin(): return redirect('/') query = {'github_id': id} update_values = {'$set': {'user_role': user_role}} users_collection.update_one(query, update_values) return redirect('/users') return app
def setup_google_authorization(app, CFG): # If any of this stuff is not set, consider # Google Authorization not being enabled. if "Google_Authorization" not in CFG.sections(): return ga_CFG = CFG["Google_Authorization"] def get_google_provider_cfg(): if ga_CFG is None: return None return requests.get(GOOGLE_DISCOVERY_URL).json() GOOGLE_CLIENT_ID = ga_CFG.get("google_client_id", "None") if GOOGLE_CLIENT_ID == "None": return GOOGLE_CLIENT_SECRET = ga_CFG.get("google_client_secret", "None") if GOOGLE_CLIENT_SECRET == "None": return GOOGLE_DISCOVERY_URL = ( "https://accounts.google.com/.well-known/openid-configuration") # OAuth2 google client setup google_client = WebApplicationClient(GOOGLE_CLIENT_ID) @app.route("/login_google") def login_google(): if is_authenticated(session, request): return redirect(url_for(".me")) # Find out what URL to hit for Google login google_provider_cfg = get_google_provider_cfg() if google_provider_cfg is None: return global_vars.redirect_error( "Google Authentication impossible.", error_code=400) authorization_endpoint = google_provider_cfg["authorization_endpoint"] # Use library to construct the request for Google login and provide # scopes that let you retrieve user's profile from Google request_uri = google_client.prepare_request_uri( authorization_endpoint, redirect_uri=request.base_url + "/callback", scope=["openid", "email", "profile"], ) return redirect(request_uri) @app.route("/login_google/callback") def callback(): if is_authenticated(session, request): return redirect(url_for(".me")) # Authorization code Google sent back. auth_code = request.args.get("code") google_provider_cfg = get_google_provider_cfg() if google_provider_cfg is None: return global_vars.redirect_error( "Google Authentication impossible.", error_code=400) # Getting a URL to hit to get tokens that allow to ask for access. token_endpoint = google_provider_cfg["token_endpoint"] # Prepare and send a request to get the token. token_url, headers, body = google_client.prepare_token_request( token_endpoint, authorization_response=request.url, redirect_url=request.base_url, code=auth_code, ) token_response = requests.post( token_url, headers=headers, data=body, auth=(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET), ) # Parse the token. google_client.parse_request_body_response( json.dumps(token_response.json())) # Getting a URL that will provide all user information. userinfo_endpoint = google_provider_cfg["userinfo_endpoint"] uri, headers, body = google_client.add_token(userinfo_endpoint) userinfo_response = requests.get(uri, headers=headers, data=body).json() # Checking whether user's email is actually verified. if userinfo_response.get("email_verified"): unique_id = userinfo_response["sub"] users_email = userinfo_response["email"] picture = userinfo_response["picture"] users_name = userinfo_response["given_name"] else: return global_vars.redirect_error( "User email not available or not verified by Google.", 400) # Try to find a User_Info matching this id in DB. user = User_Info.get(google_id=unique_id) if user is None: user = User_Info( name=users_name, email=users_email, profile_pic=picture, google_id=unique_id, ) user.insert() """ session_info = user.insert() session["user_id"] = user.user_id session["key"] = session_info["key"] """ # Begin user session by logging the user in login_user(user, remember=True) client = global_vars.clients_by_sid[request.sid] client.user_info = user client.client_info.user_id = user.user_id # Send user back to homepage return redirect(url_for(".me"))
login_user, logout_user, ) app = Flask(__name__, template_folder='templates') # We can make this secret key as environ variable later to sign cookies app.secret_key = "test" #os.environ.get("SECRET_KEY")# or os.urandom(24) app.config["MONGO_URI"] = "mongodb://*****:*****@app.route("/") def index(): if 'user_id' in session: print(session['user_id']) return render_template("index.html") @app.route("/postings") def postings(): # If not logged in, show Login button
import os import json import requests from flask_login import LoginManager from oauthlib.oauth2 import WebApplicationClient from support.config import GoogleOAuth login_manager = LoginManager() oauth = GoogleOAuth() client = WebApplicationClient(oauth.GOOGLE_CLIENT_ID) def get_google_provider_cfg(): return requests.get(oauth.GOOGLE_DISCOVERY_URL).json()
import requests import datetime from bson.json_util import dumps from bson.json_util import loads from todo_app.flask_config import Config from todo_app.classModels import Item, ViewModel, User import pymongo from werkzeug.exceptions import Forbidden import logging from loggly.handlers import HTTPSHandler from logging import Formatter client_id = os.getenv("client_id") client_secret = os.getenv("client_secret") redirect_uri_value = os.getenv("redirect_uri") client = WebApplicationClient(client_id) def create_app(): app = Flask(__name__) app.config.from_object(Config) sess = Session() app.secret_key = os.getenv("SECRET_KEY") app.logger.setLevel(app.config['LOG_LEVEL']) app.config['SESSION_TYPE'] = 'filesystem' sess.init_app(app) if app.config['LOGGLY_TOKEN'] is not None: handler = HTTPSHandler(f'https://logs-01.loggly.com/inputs/{app.config["LOGGLY_TOKEN"]}/tag/todo-app') handler.setFormatter(Formatter("[%(asctime)s] %(levelname)s in %(module)s: %(message)s")) app.logger.addHandler(handler) collection=os.getenv("MONGO_COLLECTION") mongo_val = pymongo.MongoClient(os.getenv("MONGODB_CONNECTION_STRING"))
print("Required environment variables are not set. Exiting...") exit(0) logging.basicConfig(filename=config['PATH_TO_LOG_FILE'], level=logging.INFO, format=config['LOG_FORMAT']) LOGGER = logging.getLogger() LOGGER.info("All the environment variable required are set") # Flask app setup app = Flask(__name__) app.secret_key = os.environ.get("SECRET_KEY") or os.urandom(24) # OAuth 2 client setup CLIENT = WebApplicationClient(config['CLIENT_ID']) # -------------------------- ROUTES ------------------------------- @app.route("/") def home(): LOGGER.info("Home page accessed") return render_template('connect.html') @app.route("/login") def login(): LOGGER.info( "Client requested to connect to Xero. Fetching Xero request URL from Xero" ) request_uri = CLIENT.prepare_request_uri(
def get_google_client(): google_client_id = get_google_client_id() return WebApplicationClient(google_client_id)
import requests import os import json from API.models import User from API.model_datastore import create_user, get_user from flask import Blueprint, request, redirect, url_for, session from flask_login import (login_required, login_user, logout_user) from oauthlib.oauth2 import WebApplicationClient """ Google Oauth is templated from https://realpython.com/flask-google-login/ The auth blueprint is used for logging in the user and handling the users session. """ auth = Blueprint('auth', __name__) client = WebApplicationClient(os.environ['GOOGLE_CLIENT_ID']) @auth.route("/login") def login(): # Find out what URL to hit for Google login google_provider_cfg = get_google_provider_cfg() authorization_endpoint = google_provider_cfg["authorization_endpoint"] # Use library to construct the request for login and provide # scopes that let you retrieve user's profile from Google request_uri = client.prepare_request_uri( authorization_endpoint, redirect_uri=fix_http(request.base_url) + "/callback", scope=["openid", "email", "profile"], ) session['url'] = request.referrer
def test_prepare_request_body(self): """ see issue #585 https://github.com/oauthlib/oauthlib/issues/585 `prepare_request_body` should support the following scenarios: 1. Include client_id alone in the body (default) 2. Include client_id and client_secret in auth and not include them in the body (RFC preferred solution) 3. Include client_id and client_secret in the body (RFC alternative solution) 4. Include client_id in the body and an empty string for client_secret. """ client = WebApplicationClient(self.client_id) # scenario 1, default behavior to include `client_id` r1 = client.prepare_request_body() self.assertEqual( r1, 'grant_type=authorization_code&client_id=%s' % self.client_id) r1b = client.prepare_request_body(include_client_id=True) self.assertEqual( r1b, 'grant_type=authorization_code&client_id=%s' % self.client_id) # scenario 2, do not include `client_id` in the body, so it can be sent in auth. r2 = client.prepare_request_body(include_client_id=False) self.assertEqual(r2, 'grant_type=authorization_code') # scenario 3, Include client_id and client_secret in the body (RFC alternative solution) # the order of kwargs being appended is not guaranteed. for brevity, check the 2 permutations instead of sorting r3 = client.prepare_request_body(client_secret=self.client_secret) r3_params = dict(urlparse.parse_qsl(r3, keep_blank_values=True)) self.assertEqual(len(r3_params.keys()), 3) self.assertEqual(r3_params['grant_type'], 'authorization_code') self.assertEqual(r3_params['client_id'], self.client_id) self.assertEqual(r3_params['client_secret'], self.client_secret) r3b = client.prepare_request_body(include_client_id=True, client_secret=self.client_secret) r3b_params = dict(urlparse.parse_qsl(r3b, keep_blank_values=True)) self.assertEqual(len(r3b_params.keys()), 3) self.assertEqual(r3b_params['grant_type'], 'authorization_code') self.assertEqual(r3b_params['client_id'], self.client_id) self.assertEqual(r3b_params['client_secret'], self.client_secret) # scenario 4, `client_secret` is an empty string r4 = client.prepare_request_body(include_client_id=True, client_secret='') r4_params = dict(urlparse.parse_qsl(r4, keep_blank_values=True)) self.assertEqual(len(r4_params.keys()), 3) self.assertEqual(r4_params['grant_type'], 'authorization_code') self.assertEqual(r4_params['client_id'], self.client_id) self.assertEqual(r4_params['client_secret'], '') # scenario 4b, `client_secret` is `None` r4b = client.prepare_request_body(include_client_id=True, client_secret=None) r4b_params = dict(urlparse.parse_qsl(r4b, keep_blank_values=True)) self.assertEqual(len(r4b_params.keys()), 2) self.assertEqual(r4b_params['grant_type'], 'authorization_code') self.assertEqual(r4b_params['client_id'], self.client_id) # scenario Warnings with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") # catch all # warning1 - raise a DeprecationWarning if a `client_id` is submitted rWarnings1 = client.prepare_request_body(client_id=self.client_id) self.assertEqual(len(w), 1) self.assertIsInstance(w[0].message, DeprecationWarning) # testing the exact warning message in Python2&Python3 is a pain # scenario Exceptions # exception1 - raise a ValueError if the a different `client_id` is submitted with self.assertRaises(ValueError) as cm: client.prepare_request_body(client_id='different_client_id')
import json from demix.utils.logging import logger_factory from demix.auth import encode from demix.config import get_cfg from demix.db import get_db from demix.utils.flask import protected, current_user, custom_error GOOGLE_DISCOVERY_URL = ( "https://accounts.google.com/.well-known/openid-configuration") auth = Blueprint( 'auth', __name__, ) cfg = get_cfg('google') # stores google secret info client = WebApplicationClient(cfg['client_id']) # needed for google def get_google_provider_cfg(): return requests.get(GOOGLE_DISCOVERY_URL).json() google_provider_cfg = get_google_provider_cfg() logger = logger_factory(__name__) db = get_db() @auth.route("/api/me") @protected def me(): user = current_user()
def get_session(self, *, state=None, redirect_uri=None, load_token=False, scopes=None): """ Create a requests Session object :param str state: session-state identifier to rebuild OAuth session (CSRF protection) :param str redirect_uri: callback URL specified in previous requests :param list(str) scopes: list of scopes we require access to :param bool load_token: load and ensure token is present :return: A ready to use requests session, or a rebuilt in-flow session :rtype: OAuth2Session """ redirect_uri = redirect_uri or self.oauth_redirect_url client_id, _ = self.auth if self.auth_flow_type == 'authorization': oauth_client = WebApplicationClient(client_id=client_id) elif self.auth_flow_type == 'credentials': oauth_client = BackendApplicationClient(client_id=client_id) else: raise ValueError( '"auth_flow_type" must be either "authorization" or "credentials"' ) requested_scopes = scopes or self.scopes if load_token: # gets a fresh token from the store token = self.token_backend.get_token() if token is None: raise RuntimeError( 'No auth token found. Authentication Flow needed') oauth_client.token = token if self.auth_flow_type == 'authorization': requested_scopes = None # the scopes are already in the token (Not if type is backend) session = OAuth2Session(client_id=client_id, client=oauth_client, token=token, scope=requested_scopes) else: session = OAuth2Session(client_id=client_id, client=oauth_client, state=state, redirect_uri=redirect_uri, scope=requested_scopes) session.proxies = self.proxy if self.request_retries: retry = Retry(total=self.request_retries, read=self.request_retries, connect=self.request_retries, backoff_factor=RETRIES_BACKOFF_FACTOR, status_forcelist=RETRIES_STATUS_LIST) adapter = HTTPAdapter(max_retries=retry) session.mount('http://', adapter) session.mount('https://', adapter) return session