def __init__(self, redirect_uri, code_challenge): super().__init__(redirect_uri, code_challenge) if not GITHUB_CLIENT_ID or not GITHUB_CLIENT_SECRET: raise Exception("GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET should be set via environment") self._github = GithubClient(client_id=GITHUB_CLIENT_ID, client_secret=GITHUB_CLIENT_SECRET)
async def auth_handler(request): session = await get_session(request) params = urllib.parse.parse_qs(request.query_string) user = session.get('User') if user: # Already authenticated request['user'] = user elif handler in whitelist_handlers: # We don't need authentication pass elif handler == handle_github_callback and \ session.get('github_state'): # Attempting to authenticate - let them pass through pass elif api_unauthorized and request.path.startswith('/api/'): return web.HTTPUnauthorized() else: gh = GithubClient( client_id=gh_id, client_secret=gh_secret ) state = os.urandom(30).hex() authorize_url = gh.get_authorize_url( scope='user:email read:org', state=state) session['github_state'] = state session['desired_location'] = request.path return web.HTTPFound(authorize_url) return await handler(request)
async def auth_handler(request): session = await get_session(request) params = urllib.parse.parse_qs(request.query_string) user = session.get('User') if user: # Already authenticated request['user'] = user elif handler in whitelist_handlers: # We don't need authentication pass elif handler == handle_github_callback and \ session.get('github_state'): # Attempting to authenticate - let them pass through pass elif api_unauthorized and request.path.startswith('/api/'): return web.HTTPUnauthorized() else: gh = GithubClient(client_id=gh_id, client_secret=gh_secret) state = os.urandom(30).hex() authorize_url = gh.get_authorize_url( scope='user:email read:org', state=state) session['github_state'] = state session['desired_location'] = request.path return web.HTTPFound(authorize_url) return await handler(request)
async def handle_oauth_callback(self, request, session) -> dict: params = request.query gh = GithubClient(client_id=self._id, client_secret=self._secret) code = params.get('code') if not code: raise BadAttemptError("No github code found. It's possible the " "session timed out while authenticating.") otoken, _ = await gh.get_access_token(code) gh = GithubClient( # Need a new client, so it includes the new access token client_id=self._id, client_secret=self._secret, access_token=otoken) req = await gh.request('GET', 'user') user = await req.json() req.close() req = await gh.request('GET', 'user/orgs') orgs = await req.json() req.close() for org in orgs: if org.get('login') == self.org: user['username'] = user.get('login') return user raise BadAttemptError('User not in correct Org')
async def test_oauth2(http, response): from aioauth_client import GithubClient, ClientRegistry github = GithubClient(client_id='cid', client_secret='csecret') assert github assert 'github' in ClientRegistry.clients assert github.get_authorize_url( ) == 'https://github.com/login/oauth/authorize?client_id=cid&response_type=code' # noqa http.return_value = response(json={'access_token': 'TEST-TOKEN'}) token, meta = await github.get_access_token('000') assert token == 'TEST-TOKEN' assert meta assert http.called http.reset_mock() http.return_value = response(json={'access_token': 'TEST-TOKEN'}) res = await github.request('GET', 'user', access_token='NEW-TEST-TOKEN') assert res http.assert_called_with( 'GET', 'https://api.github.com/user', params=None, headers={ 'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', 'Authorization': 'Bearer NEW-TEST-TOKEN' })
def github(request): github = GithubClient( client_id='b6281b6fe88fa4c313e6', client_secret='21ff23d9f1cad775daee6a38d230e1ee05b04f7c', ) if 'code' not in request.GET: return web.HTTPFound(github.get_authorize_url(scope='user:email')) # Get access token code = request.GET['code'] token = yield from github.get_access_token(code) # Get a resource response = yield from github.request('GET', 'user') body = yield from response.read() return web.Response(body=body, content_type='application/json')
async def github(request): github = GithubClient( client_id='b6281b6fe88fa4c313e6', client_secret='21ff23d9f1cad775daee6a38d230e1ee05b04f7c', ) if 'code' not in request.url.query: return ResponseRedirect(github.get_authorize_url(scope='user:email')) # Get access token code = request.url.query['code'] token, _ = await github.get_access_token(code) assert token # Get a resource `https://api.github.com/user` response = await github.request('GET', 'user') return await response.read()
def github(request): github = GithubClient( client_id='b6281b6fe88fa4c313e6', client_secret='21ff23d9f1cad775daee6a38d230e1ee05b04f7c', ) if 'code' not in request.query: return web.HTTPFound(github.get_authorize_url(scope='user:email')) # Get access token code = request.query['code'] token, _ = yield from github.get_access_token(code) assert token # Get a resource `https://api.github.com/user` response = yield from github.request('GET', 'user') body = yield from response.read() return web.Response(body=body, content_type='application/json')
async def github_auth(request): github = GithubClient( client_id=config.GITHUB_CLIENT_ID, client_secret=config.GITHUB_CLIENT_SECRET, ) session = await aiohttp_session.get_session(request) if 'code' not in request.query: redirect_uri = request.query.get('redirect_uri', '/') session['redirect_uri'] = redirect_uri return web.HTTPFound(github.get_authorize_url(scope='user:email')) code = request.query['code'] token, _ = await github.get_access_token(code) session['token'] = token next_uri = session.pop('redirect_uri', '/') logger.debug('Redirecting back to %s', next_uri) return web.HTTPFound(next_uri)
async def wrapped(request, **kwargs): session = await get_session(request) if 'token' not in session: return web.HTTPFound('/auth?redirect_uri={}'.format(request.url)) github = GithubClient(client_id=config.GITHUB_CLIENT_ID, client_secret=config.GITHUB_CLIENT_SECRET, access_token=session['token']) user, info = await github.user_info() return await fn(request, user, **kwargs)
async def handle_github_callback(request): params = urllib.parse.parse_qs(request.query_string) session = await get_session(request) # Check conditions if (session.get('github_state') != # Github_state is incorrect params.get('state', [None])[0]): print('bad state returned') """ Codes are the same, we are in the middle of authenticating and things look ok, carry on """ return web.HTTPForbidden() gh = GithubClient(client_id=gh_id, client_secret=gh_secret) code = params.get('code', [None])[0] if not code: return web.HTTPNotFound(body=b'Page not found. Its possible the ' b'session timed out while authenticating.') otoken, _ = await gh.get_access_token(code) gh = GithubClient(client_id=gh_id, client_secret=gh_secret, access_token=otoken) req = await gh.request('GET', 'user') user = await req.json() req.close() req = await gh.request('GET', 'user/orgs') orgs = await req.json() req.close() for org in orgs: if org.get('login') == gh_org: # Swap github_state for user session.pop('github_state', None) session['User'] = user.get('login') location = session.pop('desired_location') return web.HTTPFound(location) return web.HTTPForbidden()
async def test_custom_client(http, response): from aioauth_client import GithubClient transport = AsyncClient() github = GithubClient(client_id='cid', client_secret='csecret', transport=transport) assert github.transport http.return_value = response(json={'access_token': 'TOKEN'}) token, meta = await github.get_access_token('000') assert http.called assert meta assert token
class GithubAuth: def __init__(self, client_id, client_secret): self.client_id = client_id self.__client_secret = client_secret self.client = GithubClient(client_id, client_secret) def auth_url(self): # user:email might be enough here return self.client.get_authorize_url(scope="user") async def get_token(self, code): return await self.client.get_access_token(code) def api(self, token): return GithubAPI(token)
async def test_oauth2_request(http): from aioauth_client import GithubClient github = GithubClient(client_id='cid', client_secret='csecret', access_token='token') res = await github.request('GET', '/user', params={'test': 'ok'}) assert res http.assert_called_with( 'GET', 'https://api.github.com/user', params={'test': 'ok'}, headers={ 'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', 'Authorization': 'Bearer token' })
def __init__(self, client_id, client_secret): self.client_id = client_id self.__client_secret = client_secret self.client = GithubClient(client_id, client_secret)
async def get_oauth_url(self, request, session, state): gh = GithubClient(client_id=self._id, client_secret=self._secret) authorize_url = gh.get_authorize_url(scope='user:email read:org', state=state) return authorize_url
def gh_client(**kw): return GithubClient(conf['github_id'], conf['github_secret'], **kw)
class User(BaseUser): method = "github" routes = web.RouteTableDef() def __init__(self, redirect_uri, code_challenge): super().__init__(redirect_uri, code_challenge) if not GITHUB_CLIENT_ID or not GITHUB_CLIENT_SECRET: raise Exception("GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET should be set via environment") self._github = GithubClient(client_id=GITHUB_CLIENT_ID, client_secret=GITHUB_CLIENT_SECRET) def get_authorize_page(self): # Chance on collision is really low, but would be really annoying. So # simply protect against it by looking for an unused UUID. state = secrets.token_hex(16) while state in _github_states: state = secrets.token_hex(16) self._state = state _github_states[self._state] = self # We don't set any scope, as we only want the username + id authorize_url = self._github.get_authorize_url(state=self._state) return web.HTTPFound(location=authorize_url) @staticmethod def get_by_state(state): if state not in _github_states: return None user = _github_states[state] user._forget_github_state() return user def logout(self): self._forget_github_state() super().logout() def _forget_github_state(self): if self._state: del _github_states[self._state] self._state = None async def get_user_information(self, code): # Validate the code and fetch the user info await self._github.get_access_token(code) user, _ = await self._github.user_info() self.display_name = user.username self.id = str(user.id) @staticmethod @routes.get("/user/github-callback") async def login_github_callback(request): code = in_query_github_code(request.query.get("code")) state = in_query_github_state(request.query.get("state")) user = User.get_by_state(state) if user is None: return web.HTTPNotFound() await user.get_user_information(code) return web.HTTPFound(location=f"{user.redirect_uri}?code={user.code}") @staticmethod def get_description(): return "Login via GitHub" @staticmethod def get_settings_url(): return f"https://github.com/settings/connections/applications/{GITHUB_CLIENT_ID}"
class UserOAuthView(UserViewMixin, PeeweeView): model = UserOAuth github = GithubClient(client_id='config.CLIENT_ID', client_secret='config.CLIENT_SECRET') @app.route.interface('GET') async def get_oauth_url(self): authorize_url = self.github.get_authorize_url(scope="user:email") self.finish(RETCODE.SUCCESS, {'state': 0, 'url': authorize_url}) @app.route.interface('GET') async def get_user_data(self): code = self.params print(code) code = code['code'] if code == 'undefined': self.finish(RETCODE.FAILED) return otoken, _ = await self.github.get_access_token(code) github = GithubClient( client_id=config.CLIENT_ID, client_secret=config.CLIENT_SECRET, access_token=otoken, ) response = await github.request('GET', 'user') # response = json.loads(response) if response['id']: try: account = UserOAuth.get(UserOAuth.login_id == response['id'], UserOAuth.platform == 'github') except UserOAuth.DoesNotExist: account = None if account: if account.user_id: # 返回用户已有信息 u = UserModel.get_by_pk(account.user_id) if u: expires = 30 u.refresh_key() self.setup_user_key(u.key, expires) self.finish( RETCODE.SUCCESS, { 'oauthcode': 0, 'user_id': account.user_id, 'state': account.state, 'access_token': u.key }) else: self.finish( RETCODE.SUCCESS, { 'oauthcode': 1, 'state': account.state, 'oauth_id': account.id, 'login_id': account.login_id, 'platform': account.platform }) else: ins = [{ 'login_id': response['id'], 'time': time.time(), 'platform': 'github', 'state': POST_STATE.APPLY }] if not isinstance(config.LONG_ID_GENERATOR, config.SQLSerialGenerator): ins[0]['id'] = config.LONG_ID_GENERATOR().to_bin() UserOAuth.insert_many(ins).execute() self.finish( RETCODE.SUCCESS, { 'oauthcode': 1, 'oauth_id': ins[0]['id'], 'state': ins[0]['state'], 'login_id': ins[0]['login_id'], 'platform': ins[0]['platform'] }) else: self.finish(RETCODE.NOT_FOUND) @app.route.interface('POST') async def update(self): post = await self.post_data() print('提交的更新内容', post) try: account = UserOAuth.get(UserOAuth.login_id == post['loginId'], UserOAuth.platform == post['platform']) except UserOAuth.DoesNotExist: account = None except KeyError: account = None print('keyerror') if account: if post['state'] == str(POST_STATE.APPLY): # 该post['id']是user表中的id post_user_id = to_bin(post['id']) UserOAuth.update( user_id=post_user_id, state=POST_STATE.NORMAL).where( UserOAuth.login_id == post['loginId']).execute() self.finish(RETCODE.SUCCESS) else: print('非法参数') self.finish(RETCODE.FAILED) else: self.finish(RETCODE.FAILED) print('failed')
async def get_user_data(self): code = self.params print(code) code = code['code'] if code == 'undefined': self.finish(RETCODE.FAILED) return otoken, _ = await self.github.get_access_token(code) github = GithubClient( client_id=config.CLIENT_ID, client_secret=config.CLIENT_SECRET, access_token=otoken, ) response = await github.request('GET', 'user') # response = json.loads(response) if response['id']: try: account = UserOAuth.get(UserOAuth.login_id == response['id'], UserOAuth.platform == 'github') except UserOAuth.DoesNotExist: account = None if account: if account.user_id: # 返回用户已有信息 u = UserModel.get_by_pk(account.user_id) if u: expires = 30 u.refresh_key() self.setup_user_key(u.key, expires) self.finish( RETCODE.SUCCESS, { 'oauthcode': 0, 'user_id': account.user_id, 'state': account.state, 'access_token': u.key }) else: self.finish( RETCODE.SUCCESS, { 'oauthcode': 1, 'state': account.state, 'oauth_id': account.id, 'login_id': account.login_id, 'platform': account.platform }) else: ins = [{ 'login_id': response['id'], 'time': time.time(), 'platform': 'github', 'state': POST_STATE.APPLY }] if not isinstance(config.LONG_ID_GENERATOR, config.SQLSerialGenerator): ins[0]['id'] = config.LONG_ID_GENERATOR().to_bin() UserOAuth.insert_many(ins).execute() self.finish( RETCODE.SUCCESS, { 'oauthcode': 1, 'oauth_id': ins[0]['id'], 'state': ins[0]['state'], 'login_id': ins[0]['login_id'], 'platform': ins[0]['platform'] }) else: self.finish(RETCODE.NOT_FOUND)