async def fetch_access_token(self, code, request_handler): body = urllib_parse.urlencode({ 'redirect_uri': get_path_for_redirect(request_handler), 'code': code, 'client_id': self.client_id, 'client_secret': self.secret, 'grant_type': 'authorization_code', }) http_client = httpclient.AsyncHTTPClient() response = await http_client.fetch( self.oauth_token_url, method='POST', headers={'Content-Type': 'application/x-www-form-urlencoded'}, body=body, raise_error=False) response_values = {} if response.body: response_values = escape.json_decode(response.body) if response.error: if response_values.get('error_description'): error_text = response_values.get('error_description') elif response_values.get('error'): error_text = response_values.get('error') else: error_text = str(response.error) error_message = 'Failed to load access_token: ' + error_text LOGGER.error(error_message) raise AuthFailureError(error_message) response_values = escape.json_decode(response.body) access_token = response_values.get('access_token') if not access_token: message = 'No access token in response: ' + str(response.body) LOGGER.error(message) raise AuthFailureError(message) return access_token
async def fetch_user_groups(self, access_token): user = self.user_tokens[access_token] if user in self.failing_groups_loading: raise AuthFailureError('Emulate group loading error') if user in self.user_groups: return self.user_groups[user] return []
async def authenticate(self, request_handler): code = request_handler.get_argument('code', False) if not code: LOGGER.error('Code is not specified') raise AuthBadRequestException( 'Missing authorization information. Please contact your administrator' ) access_token = await self.fetch_access_token(code, request_handler) user_info = await self.fetch_user_info(access_token) user_email = user_info.email if not user_email: error_message = 'No email field in user response. The response: ' + str( user_info.oauth_response) LOGGER.error(error_message) raise AuthFailureError(error_message) if not user_info.enabled: error_message = 'User %s is not enabled in OAuth provider. The response: %s' \ % (user_email, str(user_info.oauth_response)) LOGGER.error(error_message) raise AuthFailureError(error_message) user_state = _UserState(user_email) self._users[user_email] = user_state if self.group_support: user_groups = await self.fetch_user_groups(access_token) LOGGER.info('Loaded groups for ' + user_email + ': ' + str(user_groups)) user_state.groups = user_groups now = time.time() if self.auth_info_ttl: request_handler.set_secure_cookie('token', access_token) user_state.last_auth_update = now user_state.last_visit = now return user_email
def get_path_for_redirect(request_handler): referer = request_handler.request.headers.get('Referer') if not referer: LOGGER.error('No referer') raise AuthFailureError('Missing request header. Please contact system administrator') parse_result = urllib_parse.urlparse(referer) protocol = parse_result[0] host = parse_result[1] path = parse_result[2] return urllib_parse.urlunparse((protocol, host, path, '', '', ''))
def read_user(self, code, request_handler): access_token = yield self.get_access_token(code, request_handler) oauth_mixin = tornado.auth.GoogleOAuth2Mixin() user_future = oauth_mixin.oauth2_request( tornado.auth.GoogleOAuth2Mixin._OAUTH_USERINFO_URL, access_token=access_token) user_response = yield user_future if user_response.get('email'): return user_response.get('email') error_message = 'No email field in user response. The response: ' + str(user_response) LOGGER.error(error_message) raise AuthFailureError(error_message)