refstack/refstack/api/utils.py

211 lines
6.5 KiB
Python

# Copyright (c) 2015 Mirantis, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Refstack API's utils."""
import copy
import random
import requests
import string
from oslo_config import cfg
from oslo_log import log
from oslo_utils import timeutils
import pecan
import six
from six.moves.urllib import parse
from refstack import db
from refstack.api import constants as const
LOG = log.getLogger(__name__)
CONF = cfg.CONF
class ParseInputsError(Exception):
"""Raise if input params are invalid."""
pass
def _get_input_params_from_request(expected_params):
"""Get input parameters from request.
:param expecred_params: (array) Expected input
params specified in constants.
"""
filters = {}
for param in expected_params:
value = pecan.request.GET.get(param)
if value is not None:
filters[param] = value
LOG.debug('Parameter %(param)s has been received '
'with value %(value)s' % {
'param': param,
'value': value
})
return filters
def parse_input_params(expected_input_params):
"""Parse input parameters from request.
:param expecred_params: (array) Expected input
params specified in constants.
"""
raw_filters = _get_input_params_from_request(expected_input_params)
filters = copy.deepcopy(raw_filters)
date_fmt = CONF.api.input_date_format
for key, value in filters.items():
if key == const.START_DATE or key == const.END_DATE:
try:
filters[key] = timeutils.parse_strtime(value, date_fmt)
except (ValueError, TypeError) as exc:
raise ParseInputsError('Invalid date format: %(exc)s'
% {'exc': exc})
start_date = filters.get(const.START_DATE)
end_date = filters.get(const.END_DATE)
if start_date and end_date:
if start_date > end_date:
raise ParseInputsError('Invalid dates: %(start)s '
'more than %(end)s' % {
'start': const.START_DATE,
'end': const.END_DATE
})
return filters
def _calculate_pages_number(per_page, records_count):
"""Return pages number.
:param per_page: (int) results number fot one page.
:param records_count: (int) total records count.
"""
quotient, remainder = divmod(records_count, per_page)
if remainder > 0:
return quotient + 1
return quotient
def get_page_number(records_count):
"""Get page number from request.
:param records_count: (int) total records count.
"""
page_number = pecan.request.GET.get(const.PAGE)
per_page = CONF.api.results_per_page
total_pages = _calculate_pages_number(per_page, records_count)
# The first page exists in any case
if page_number is None:
return (1, total_pages)
try:
page_number = int(page_number)
except (ValueError, TypeError):
raise ParseInputsError('Invalid page number: The page number can not '
'be converted to an integer')
if page_number == 1:
return (page_number, total_pages)
if page_number <= 0:
raise ParseInputsError('Invalid page number: '
'The page number less or equal zero.')
if page_number > total_pages:
raise ParseInputsError('Invalid page number: The page number '
'is greater than the total number of pages.')
return (page_number, total_pages)
def set_query_params(url, params):
"""Set params in given query."""
url_parts = parse.urlparse(url)
url = parse.urlunparse((
url_parts.scheme,
url_parts.netloc,
url_parts.path,
url_parts.params,
parse.urlencode(params),
url_parts.fragment))
return url
def get_token(length=30):
"""Get random token."""
return ''.join(random.choice(string.ascii_lowercase)
for i in range(length))
def delete_params_from_user_session(params):
"""Delete params from user session."""
session = get_user_session()
for param in params:
if session.get(param):
del session[param]
session.save()
def get_user_session():
"""Return user session."""
return pecan.request.environ['beaker.session']
def is_authenticated():
"""Return True if user is authenticated."""
session = get_user_session()
if session.get(const.USER_OPENID):
try:
if db.user_get(session.get(const.USER_OPENID)):
return True
except db.UserNotFound:
pass
return False
def verify_openid_request(request):
"""Verify OpenID returned request in OpenID."""
verify_params = dict(request.params.copy())
verify_params["openid.mode"] = "check_authentication"
verify_response = requests.post(
CONF.osid.openstack_openid_endpoint, data=verify_params,
verify=not CONF.api.app_dev_mode
)
verify_data_tokens = verify_response.content.split()
verify_dict = dict((token.split(":")[0], token.split(":")[1])
for token in verify_data_tokens)
if (verify_response.status_code / 100 != 2
or verify_dict['is_valid'] != 'true'):
pecan.abort(401, 'Authentication is failed. Try again.')
# Is the data we've received within our required parameters?
required_parameters = {
const.OPENID_NS_SREG_EMAIL: 'Please permit access to '
'your email address.',
const.OPENID_NS_SREG_FULLNAME: 'Please permit access to '
'your name.',
}
for name, error in six.iteritems(required_parameters):
if name not in verify_params or not verify_params[name]:
pecan.abort(401, 'Authentication is failed. %s' % error)
return True