Source code for linotp.lib.reply

# -*- coding: utf-8 -*-
#
#    LinOTP - the open source solution for two factor authentication
#    Copyright (C) 2010 - 2014 LSE Leading Security Experts GmbH
#
#    This file is part of LinOTP server.
#
#    This program is free software: you can redistribute it and/or
#    modify it under the terms of the GNU Affero General Public
#    License, version 3, as published by the Free Software Foundation.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the
#               GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
#
#    E-mail: linotp@lsexperts.de
#    Contact: www.linotp.org
#    Support: www.lsexperts.de
#
"""create responses"""

import qrcode
import StringIO
import urllib

try:
    import json
except ImportError:
    import simplejson as json

from pylons import request
from pylons import tmpl_context as c

from linotp.lib.error       import LinotpError
from linotp.lib.util        import get_version


optional = True
required = False

LINOTP_ERRORS = [707]

httpErr = {
        '400': 'Bad Request',
        '401': 'Unauthorized',
        '403': 'Forbidden',
        '404': 'Not Found',
        '410': 'Gone',
        '500': 'Internal Server Error',
        '501': 'Not Implemented',
        '502': 'Bad Gateway',
        '503': 'Service Unavailable',
        }

resp = """
<html>
<head>
<title>%s %s</title>
</head>
<body>
<h1>%s %s</h1>
%s
<br>
<br>
</body>
</html>
"""

import logging
log = logging.getLogger(__name__)

[docs]def sendError(response, exception, id=1, context=None): ''' sendError - return a json error result document remark: the 'context' is especially required to catch errors from the _before_ methods. The return of a _before_ must be of type response and must have the attribute response._exception set, to stop further processing, which otherwise will have ugly results!! :param response: the pylon response object :type response: response object :param exception: should be a linotp exception (s. linotp.lib.error.py) :type exception: exception :param id: id value, for future versions :type id: int :param context: default is None or 'before' :type context: string :return: json rendered sting result :rtype: string ''' ret = '' errId = -311 ## handle the different types of exception: ## Exception, LinOtpError, str/unicode if hasattr(exception, '__class__') == True \ and isinstance(exception, Exception): errDesc = unicode(exception) if isinstance(exception, LinotpError): errId = exception.getId() elif type(exception) in [str, unicode]: errDesc = unicode(exception) else: errDesc = u"%r" % exception HTTP_ERROR = False ## check if we have an additional request parameter 'httperror' ## which triggers the error to be delivered as HTTP Error try: httperror = request.params.get('httperror') except Exception as exx: httperror = "%r" % exx if httperror is not None: ## now lookup in the config, which linotp errors should be shwon as ## HTTP error linotp_errors = c.linotpConfig.get('linotp.errors', None) if linotp_errors is None: HTTP_ERROR = True else: linotp_errors = linotp_errors.split(',') if unicode(errId) in linotp_errors: HTTP_ERROR = True else: HTTP_ERROR = False if HTTP_ERROR is True: ## httperror as param exist but is not defined ## so fallback to 500 - Internal Server Error if len(httperror) == 0: httperror = '500' ## prepare the response to be of text/html response.content_type = 'text/html' response.status = httperror code = httperror status = httpErr.get(httperror, '') desc = '[%s] %d: %s' % (get_version(), errId, errDesc) ret = resp % (code, status, code, status, desc) if context in ['before', 'after']: response._exception = exception response.text = u'' + ret ret = response else: response.content_type = 'application/json' res = { "jsonrpc": "2.0", "result" : {"status": False, "error": { "code" : errId, "message" : errDesc, }, }, "version": get_version(), "id": id } ret = json.dumps(res, indent=3) if context in ['before', 'after']: response._exception = exception response.body = ret ret = response return ret
[docs]def sendResult(response, obj, id=1, opt=None): ''' sendResult - return an json result document :param response: the pylons response object :type response: response object :param obj: simple result object like dict, sting or list :type obj: dict or list or string/unicode :param id: id value, for future versions :type id: int :param opt: optional parameter, which allows to provide more detail :type opt: None or simple type like dict, list or string/unicode :return: json rendered sting result :rtype: string ''' response.content_type = 'application/json' res = { "jsonrpc": "2.0", "result": { "status": True, "value": obj, }, "version": get_version(), "id": id } if opt is not None and len(opt) > 0: res["detail"] = opt return json.dumps(res, indent=3)
[docs]def sendCSVResult(response, obj, flat_lines=False, filename="linotp-tokendata.csv"): ''' returns a CSV document of the input data (like in /admin/show) :param response: The pylons response object :param obj: The data, that gets serialized as CSV :type obj: JSON object :param flat_lines: If True the object only contains a list of the dict { 'cell': ..., 'id': ... } as in all the flexigrid functions. 'type flat_lines: boolean ''' delim = "'" response.content_type = "application/force-download" response.headers['Content-disposition'] = 'attachment; filename=%s' % filename output = u"" if not flat_lines: # Do the header for k, v in obj.get("data", {})[0].iteritems(): output += "%s%s%s, " % (delim, k, delim) output += "\n" # Do the data for row in obj.get("data", {}): for val in row.values(): if type(val) in [str, unicode]: value = val.replace("\n", " ") else: value = val output += "%s%s%s, " % (delim, value, delim) output += "\n" else: for l in obj: for elem in l.get("cell", []): output += "'%s', " % elem output += "\n" return output
[docs]def sendXMLResult(response, obj, id=1): response.content_type = 'text/xml' res = '<?xml version="1.0" encoding="UTF-8"?>\ <jsonrpc version="2.0">\ <result>\ <status>True</status>\ <value>%s</value>\ </result>\ <version>%s</version>\ <id>%s</id>\ </jsonrpc>' % (obj, get_version(), id) return res
[docs]def sendXMLError(response, exception, id=1): response.content_type = 'text/xml' if not hasattr(exception, "getId"): errId = -311 errDesc = str(exception) else: errId = exception.getId() errDesc = exception.getDescription() res = '<?xml version="1.0" encoding="UTF-8"?>\ <jsonrpc version="2.0">\ <result>\ <status>False</status>\ <error>\ <code>%s</code>\ <message>%s</message>\ </error>\ </result>\ <version>%s</version>\ <id>%s</id>\ </jsonrpc>' % (errId, errDesc, get_version(), id) return res
[docs]def sendQRImageResult(response, data, param=None, id=1, typ='html'): ''' method sendQRImageResult arguments response - the pylon response object param - the paramters of the request id - html - print qrcode wrapped by html or not ''' log.debug('[sendQRImageResult]') width = 0 alt = None ret = None if param is None: param = {} if 'qr' in param: typ = param.get('qr') del param['qr'] if 'width' in param: width = param.get('width') del param['width'] if 'alt' in param: alt = param.get('alt') del param['alt'] img_data = data if type(data) == dict: img_data = data.get('value', "") if typ in ['img', 'embed']: response.content_type = 'text/html' ret = create_img(img_data, width, alt) elif typ in ['png']: response.content_type = 'image/png' ret = create_png(img_data) response.content_length = len(ret) else: response.content_type = 'text/html' ret = create_html(img_data, width, param) log.debug('[sendQRImageResult]:') return ret
[docs]def create_png(data, alt=None): ''' ''' img = qrcode.make(data) output = StringIO.StringIO() img.save(output) o_data = output.getvalue() output.close() return o_data
[docs]def create_img(data, width=0, alt=None): ''' _create_img - create the qr image data :param data: input data that will be munched into the qrcode :type data: string :param width: image width in pixel :type width: int :return: <img/> taged data :rtype: string ''' width_str = '' alt_str = '' o_data = create_png(data, alt=alt) data_uri = o_data.encode("base64").replace("\n", "") if width != 0: width_str = " width=%d " % (int(width)) if alt is not None: val = urllib.urlencode({'alt':alt}) alt_str = " alt=%r " % (val[len('alt='):]) ret_img = '<img %s %s src="data:image/png;base64,%s"/>' % (alt_str, width_str, data_uri) return ret_img
[docs]def create_html(data, width=0, alt=None): ''' _create_html - create the qr image data embeded in html tag :param data: input data that will be munched into the qrcode :type data: string :param width: image width in pixel :type width: int :return: <img/> taged data :rtype: string ''' alt_str = '' img = create_img(data, width=width, alt=alt) if alt is not None: if type(alt) in (str, u''): alt_str = '<p>%s</p>' % alt elif type(alt) == dict: alta = [] for k in alt.keys(): alta.append('<li> %s:%s </li>' % (k, alt.get(k))) alt_str = '<ul>%s</ul>' % " ".join(alta) elif type(alt) == list: alta = [] for k in alt: alta.append('<li> %s </li>' % (k)) ret_html = '<html><body>%s%s</body></html>' % (img , alt_str) return ret_html #eof#######################################################