Source code for linotp.controllers.system

# -*- 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
#
"""
system controller - to configure the system
"""

try:
    import json
except ImportError:
    import simplejson as json

import re
import webob
import binascii

from linotp.lib.selftest import isSelfTest
from pylons import request, response, config, tmpl_context as c

from linotp.model.meta import Session

from linotp.lib.base import BaseController

from linotp.lib.config  import storeConfig
from linotp.lib.config  import getLinotpConfig
from linotp.lib.config  import getFromConfig
from linotp.lib.config  import updateConfig
from linotp.lib.config  import removeFromConfig

from linotp.lib.realm  import setDefaultRealm
from linotp.lib.realm  import isRealmDefined


from linotp.lib.util  import check_session
from linotp.lib.util import get_client
from linotp.lib.util import get_version_number

from linotp.lib.resolver import defineResolver
from linotp.lib.resolver import checkResolverType
from linotp.lib.resolver import getResolverList
from linotp.lib.resolver import getResolverInfo
from linotp.lib.resolver import deleteResolver

from linotp.lib.error   import ParameterError

from linotp.lib.util    import getParam, getLowerParams
from linotp.lib.reply   import sendResult, sendError, sendXMLResult, sendXMLError
from linotp.lib.realm   import getRealms
from linotp.lib.realm   import getDefaultRealm
from linotp.lib.user    import setRealm
from linotp.lib.user    import getUserFromRequest

from linotp.lib.realm   import deleteRealm
from linotp.lib.token   import newToken

from linotp.lib.policy import checkPolicyPre
from linotp.lib.policy import checkPolicyPost
from linotp.lib.policy import PolicyException

from linotp.lib.policy import getPolicy
from linotp.lib.policy import setPolicy
from linotp.lib.policy import deletePolicy
from linotp.lib.policy import getPolicyDefinitions
from linotp.lib.policy import create_policy_export_file
from linotp.lib.policy import get_client_policy

from paste.fileapp import FileApp
from cgi import escape
from pylons.i18n.translation import _

audit = config.get('audit')

import traceback
import logging
log = logging.getLogger(__name__)

optional = True
required = False


[docs]class SystemController(BaseController): ''' The linotp.controllers are the implementation of the web-API to talk to the LinOTP server. The SystemController is used to configure the LinOTP server. The functions of the SystemController are invoked like this https://server/system/<functionname> The functions are described below in more detail. ''' def __before__(self, action, **params): ''' __before__ is called before every action so we can check the authorization (fixed?) :param action: name of the to be called action :param params: the list of http parameters :return: return response :rtype: pylon response ''' log.debug("[__before__::%r] %r" % (action, params)) try: audit.initialize() c.audit['success'] = False c.audit['client'] = get_client() ## check session might raise an abort() check_session() # check authorization if action not in ["_add_dynamic_tokens", 'setupSecurityModule', 'getSupportInfo']: checkPolicyPre('system', action) ## default return for the __before__ and __after__ return response except PolicyException as pex: log.error("[__before__::%r] policy exception %r" % (action, pex)) log.error("[__before__] %s" % traceback.format_exc()) Session.rollback() Session.close() return sendError(response, pex, context='before') except webob.exc.HTTPUnauthorized as acc: ## the exception, when an abort() is called if forwarded log.error("[__before__::%r] webob.exception %r" % (action, acc)) log.error("[__before__] %s" % traceback.format_exc()) Session.rollback() Session.close() raise acc except Exception as exx: log.error("[__before__::%r] exception %r" % (action, exx)) log.error("[__before__] %s" % traceback.format_exc()) Session.rollback() Session.close() return sendError(response, exx, context='before') finally: log.debug("[__before__::%r] done" % (action)) def __after__(self): ''' __after is called after every action :return: return the response :rtype: pylons response ''' try: c.audit['administrator'] = getUserFromRequest(request).get("login") audit.log(c.audit) ## default return for the __before__ and __after__ return response except Exception as exx: log.error("[__after__] exception %r" % (exx)) log.error("[__after__] %s" % traceback.format_exc()) Session.rollback() Session.close() return sendError(response, exx, context='after') finally: log.debug("[__after__] done") ########################################################
[docs] def setDefault(self): """ method: system/set description: define default settings for tokens. These default settings are used when new tokens are generated. The default settings will not affect already enrolled tokens. arguments: DefaultMaxFailCount - Default value for the maximum allowed authentication failures DefaultSyncWindow - Default value for the synchronization window DefaultCountWindow - Default value for the coutner window DefaultOtpLen - Default value for the OTP value length -- usuall 6 or 8 DefaultResetFailCount - Default value, if the FailCounter should be reset on successful authentication [True|False] returns: a json result with a boolean "result": true exception: if an error occurs an exception is serialized and returned """ res = {} count = 0 description = "setDefault: parameters are\ DefaultMaxFailCount\ DefaultSyncWindow\ DefaultCountWindow\ DefaultOtpLen\ DefaultResetFailCount\ " keys = [ "DefaultMaxFailCount", "DefaultSyncWindow", "DefaultCountWindow", "DefaultOtpLen", "DefaultResetFailCount"] ### config settings from here try: param = getLowerParams(request.params) log.info("[setDefault] saving default configuration: %r" % param) for k in keys: if param.has_key(k.lower()): value = getParam(param, k.lower(), required) ret = storeConfig(k, value) des = "set " + k res[des] = ret count = count + 1 c.audit['success'] = count c.audit['info'] += "%s=%s, " % (k, value) if count == 0 : log.warning("[setDefault] Failed saving config. Could not find any known parameter. %s" % description) raise ParameterError("Usage: %s" % description, id=77) Session.commit() return sendResult(response, res) except Exception as exx: log.error('[setDefault] commit failed: %r' % exx) log.error("[setDefault] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.debug('[setDefault] done') ########################################################
[docs] def setConfig(self): """ set a configuration key or a set of configuration entries parameter could either be in the form key=..&value=.. or as a set of generic keyname=value pairs. .. note:: In case of key-value pairs the type information could be provided by an additional parameter with same keyname with the postfix ".type". Value could then be 'password' to trigger the storing of the value in an encrypted form :param key: configuration entry name :param value: configuration value :param type: type of the value: int or string/text or password password will trigger to store the encrypted value :param description: additional information for this config entry or :param key-value pairs: pair of &keyname=value pairs :return: a json result with a boolean "result": true """ res = {} param = {} try: param.update(request.params) log.info("[setConfig] saving configuration: %r" % param) if "key" in param: key = param.get("key") or None val = param.get("value", None) typ = param.get("type", None) des = param.get("description", None) if val is None or key is None: raise ParameterError("Required parameters: value and key") ret = storeConfig(key, val, typ, des) string = "setConfig %s" % key res[string] = ret c.audit['success'] = True c.audit['info'] = "%s=%s" % (key, val) else: ## we gather all key value pairs in the conf dict conf = {} for key in param: if key == 'session': continue val = param.get(key, '') or '' Key = key if not key.startswith('linotp'): Key = 'linotp.' + key conf[Key] = val string = "setConfig " + key + ":" + val res[string] = True c.audit['success'] = True c.audit['info'] += "%s=%s, " % (key, val) updateConfig(conf) Session.commit() return sendResult(response, res, 1) except Exception as exx: log.error("[setConfig] error saving config: %r" % exx) log.error("[setConfig] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.debug("[setConfig] done") ########################################################
[docs] def delConfig(self): """ delete a configuration key * if an error occurs an exception is serializedsetConfig and returned :param key: configuration key name :returns: a json result with the deleted value """ res = {} try: param = getLowerParams(request.params) log.info("[delConfig] with params: %r" % param) key = getParam(param, "key", required) ret = removeFromConfig(key) string = "delConfig " + key res[string] = ret c.audit['success'] = ret c.audit['info'] = key Session.commit() return sendResult(response, res, 1) except Exception as exx: log.error("[delConfig] error deleting config: %r" % exx) log.error("[delConfig] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.debug("[delConfig] done") ######################################################## ########################################################
[docs] def getConfig(self): """ retrieve value of a defined configuration key, or if no key is given, the complete configuration is returned if an error occurs an exception is serialized and returned * remark: the assumption is, that the access to system/getConfig is only allowed to privileged users :param key: generic configuration entry name (optional) :return: a json result with key value or all key + value pairs """ res = {} param = {} try: param.update(request.params) log.debug("[getConfig] with params: %r" % param) if 'session' in param: del param['session'] ## if there is no parameter, we return them all if len(param) == 0: conf = getLinotpConfig() keys = conf.keys() keys.sort() for key in keys: if key.startswith("enclinotp."): continue if key.startswith("linotp."): Key = key[len("linotp."):] typ = type(conf.get(key)).__name__ if typ not in ['str', 'unicode']: if typ == 'datetime': res[Key] = unicode(conf.get(key)) else: res[Key] = conf.get(key) else: res[Key] = conf.get(key) ## as we return the decrypted values, we could do this in place ## and display the value under the original key for key in keys: if key.startswith("enclinotp."): Key = key[len("enclinotp."):] res[Key] = conf.get(key) c.audit['success'] = True c.audit['info'] = "complete config" else: key = getParam(param, "key", required) ret = getFromConfig(key) string = "getConfig " + key res[string] = ret c.audit['success'] = ret c.audit['info'] = "config key %s" % key Session.commit() return sendResult(response, res, 1) except Exception as exx: log.error("[getConfig] error getting config: %r" % exx) log.error("[getConfig] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.debug("[getConfig] done") ########################################################
[docs] def getRealms(self): ''' method: system/getRealms description: returns all realm definitinos as a json result. arguments: returns: a json result with a list of Realms exception: if an error occurs an exception is serialized and returned Either the admin has the policy scope=system, action=read or he is rights in scope=admin for some realms. If he does not have the system-read-right, then he will only see the realms, he is admin of. ''' ### config settings from here try: param = getLowerParams(request.params) log.debug("[getRealms] with params: %r" % param) res = getRealms() c.audit['success'] = True # If the admin is not allowed to see all realms, (policy scope=system, action=read) # the realms, where he has no administrative rights need, to be stripped. polPost = checkPolicyPost('system', 'getRealms', { 'realms' : res }) res = polPost['realms'] Session.commit() return sendResult(response, res, 1) except PolicyException as pex: log.error("[getRealms] policy exception: %r" % pex) log.error("[getRealms] %s" % traceback.format_exc()) Session.rollback() return sendError(response, pex) except Exception as exx: log.error("[getRealms] error getting realms: %r" % exx) log.error("[getRealms] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.debug("[getRealms] done") ########################################################
[docs] def setResolver(self): """ method: system/setResolver description: creates or updates a useridresolver arguments: name - the name of the resolver type - the type of the resolver [ldapsersolver, sqlresolver] LDAP: LDAPURI LDAPBASE BINDDN BINDPW TIMEOUT SIZELIMIT LOGINNAMEATTRIBUTE LDAPSEARCHFILTER LDAPFILTER USERINFO NOREFERRALS - True|False SQL: Database Driver Server Port User Password Table Map returns: a json result with the found value exception: if an error occurs an exception is serialized and returned """ res = {} param = {} try: param.update(request.params) log.info("[setResolver] saving configuration: %r" % param) res = defineResolver(param) Session.commit() return sendResult(response, res, 1) except Exception as exx: log.error("[setResolver] error saving config: %r" % exx) log.error("[setResolver] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.debug('[setResolver] done') ########################################################
[docs] def getResolvers(self): """ method: system/getResolvers descriptions: returns a json list of all useridresolvers arguments: returns: a json result with a list of all available resolvers exception: if an error occurs an exception is serialized and returned """ res = {} try: log.debug("[getResolvers] calling functions getResolvers") res = getResolverList() c.audit['success'] = True Session.commit() return sendResult(response, res, 1) except Exception as exx: log.error("[getResolvers] error getting resolvers: %r" % exx) log.error("[getResolvers] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.debug("[getResolvers] done") ########################################################
[docs] def delResolver(self): """ method: system/delResolver description: this function deletes an existing resolver All config keys of this resolver get deleted arguments: resolver - the name of the resolver to delete. returns: success state exception: if an error occurs an exception is serialized and returned """ res = {} try: param = getLowerParams(request.params) log.info("[delResolver] deleting resolver: %r" % param) resolver = getParam(param, "resolver", required) ### only delete a resolver, if it is not used by any realm found = False fRealms = [] realms = getRealms() for realm in realms: info = realms.get(realm) reso = info.get('useridresolver') for idRes in reso: parts = idRes.split('.') if len(parts) == 4 and resolver == parts[3]: fRealms.append(realm) found = True if found == True: c.audit['failed'] = res err = 'Resolver %r still in use by the realms: %r' % \ (resolver, fRealms) c.audit['info'] = err raise Exception('%r !' % err) res = deleteResolver(resolver) c.audit['success'] = res c.audit['info'] = resolver Session.commit() return sendResult(response, res, 1) except Exception as exx: log.error("[delResolver] error deleting resolver: %r" % exx) log.error("[delResolver] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.debug("[delResolver] done") ########################################################
[docs] def getResolver(self): """ method: system/getResolver description: this function retrieves the definition of the resolver arguments: resolver - the name of the resolver returns: a json result with the configuration of a specified resolver exception: if an error occurs an exception is serialized and returned """ res = {} try: param = getLowerParams(request.params) log.debug("[getResolver] with param: %r" % param) resolver = getParam(param, "resolver", required) if (len(resolver) == 0): raise Exception ("[getResolver] missing resolver name") res = getResolverInfo(resolver) c.audit['success'] = True c.audit['info'] = resolver Session.commit() return sendResult(response, res, 1) except Exception as exx: log.error("[getResolver] error getting resolver: %r" % exx) log.error("[getResolver] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.debug('[getResolver] done') ########################################################
[docs] def setDefaultRealm(self): """ method: system/setDefaultRealm description: this function sets the given realm to the default realm arguments: realm - the name of the realm, that should be the default realm returns: a json result with a list of Realms exception: if an error occurs an exception is serialized and returned """ res = False try: param = getLowerParams(request.params) log.info("[setDefaultRealm] with param: %r" % param) defRealm = getParam(param, "realm", optional) if defRealm is None: defRealm = "" defRealm = defRealm.lower().strip() res = setDefaultRealm(defRealm) if res == False and defRealm != "" : c.audit['info'] = "The realm %s does not exist" % defRealm c.audit['success'] = True c.audit['info'] = defRealm Session.commit() return sendResult(response, res, 1) except Exception as exx: log.error("[setDefaultRealm] setting default realm failed: %r" % exx) log.error("[setDefaultRealm] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.debug('[setDefaultRealm] done') ########################################################
[docs] def getDefaultRealm(self): """ method: system/getDefaultRealm description: this function returns the default realm arguments: ./. returns: a json description of the default realm exception: if an error occurs an exception is serialized and returned """ res = False try: defRealm = getDefaultRealm() res = getRealms(defRealm) c.audit['success'] = True c.audit['info'] = defRealm Session.commit() return sendResult(response, res, 1) except Exception as exx: log.error("[getDefaultRealm] return default realm failed: %r" % exx) log.error("[getDefaultRealm] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.debug("[getDefaultRealm] done") ########################################################
[docs] def setRealm(self): """ method: system/setRealm description: this function is used to define a realm with the given useridresolvers arguments: * realm - name of the realm * resolvers - comma separated list of resolvers, that should be in this realm returns: a json result with a list of Realms exception: if an error occurs an exception is serialized and returned """ res = False err = "" realm = "" param = {} try: param.update(request.params) log.info("[setRealm] setting a realm: %r" % param) realm = getParam(param, "realm", required) resolvers = getParam(param, "resolvers", required) realm_resolvers = [] for resolver in resolvers.split(','): ## check resolver returns the correct resolver description (res, realm_resolver) = checkResolverType(resolver) if res == False: raise Exception("unknown resolver %r or invalid resolver " "class specification " % resolver) realm_resolvers.append(realm_resolver) resolvers = ",".join(realm_resolvers) res = setRealm(realm, resolvers) c.audit['success'] = res c.audit['info'] = "realm: %r, resolvers: %r" % (realm, resolvers) Session.commit() return sendResult(response, res, 1) except Exception as exx: err = ("Failed to set realm with %r " % param) log.error("[setRealm] %r %r" % (err, exx)) log.error("[setRealm] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.debug("[setRealm] done") ########################################################
[docs] def delRealm(self): """ method: system/delRealm description: this function deletes the given realm arguments: realm - the name of the realm to be deleted returns: a json result if deleting the realm was successful exception: if an error occurs an exception is serialized and returned """ res = {} try: param = request.params log.info("[delRealm] deleting realm: %r " % param) realm = getParam(param, "realm", required) ## we test if before delete there has been a default ## if yes - check after delete, if still one there ## and set the last available to default defRealm = getDefaultRealm() hadDefRealmBefore = False if defRealm != "": hadDefRealmBefore = True ## now test if realm is defined if isRealmDefined(realm) == True: if realm.lower() == defRealm.lower(): setDefaultRealm("") if realm == "_default_": realmConfig = "useridresolver" else: realmConfig = "useridresolver.group." + realm res["delRealm"] = {"result":removeFromConfig(realmConfig, iCase=True)} ret = deleteRealm(realm) if hadDefRealmBefore == True: defRealm = getDefaultRealm() if defRealm == "": realms = getRealms() if len(realms) == 1: for k in realms: setDefaultRealm(k) c.audit['success'] = ret c.audit['info'] = realm Session.commit() return sendResult(response, res, 1) except Exception as exx: log.error("[delRealm] error deleting realm: %r" % exx) log.error("[delRealm] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.debug("[delRealm] done") ########################################################
[docs] def setPolicy(self): """ method: system/setPolicy description: Stores a policy that define ACL or behaviour of several different actions in LinOTP. The policy is stored as configuration values like this:: Policy.<NAME>.action Policy.<NAME>.scope Policy.<NAME>.realm arguments: name: name of the policy action: which action may be executed scope: selfservice realm: This polcy holds for this realm user: (optional) This polcy binds to this user time: (optional) on which time does this policy hold client: (optional) for which requesting client this should be returns: a json result with success or error exception: if an error occurs an exception is serialized and returned """ res = {} param = {} try: log.debug("[setPolicy] params: %r" % request.params) param.update(request.params) if 'session' in param: del param['session'] name = getParam(param, "name", required) # check that the name does not contain a . if not re.match('^[a-zA-Z0-9_]*$', name): raise Exception (_("The name of the policy may only contain the characters a-zA-Z0-9_")) if not name: raise Exception (_("The name of the policy must not be empty")) action = getParam(param, "action", required) scope = getParam(param, "scope", required) realm = getParam(param, "realm", required) user = getParam(param, "user", optional) time = getParam(param, "time", optional) client = getParam(param, "client", optional) active = getParam(param, "active", optional) p_param = { 'name': name, 'action' : action, 'scope' : scope, 'realm' : realm, 'user' : user, 'time' : time, 'client': client, 'active' : active} c.audit['action_detail'] = unicode(param) if len(name) > 0 and len(action) > 0: log.debug("[setPolicy] saving policy %r" % p_param) ret = setPolicy(p_param) log.debug("[setPolicy] policy %s successfully saved." % name) string = "setPolicy " + name res[string] = ret c.audit['success'] = True Session.commit() else: log.error("[setPolicy] failed: policy with empty name or action %r" % p_param) string = "setPolicy <%r>" % name res[string] = False c.audit['success'] = False raise Exception('setPolicy failed: name and action required!') return sendResult(response, res, 1) except Exception as exx: log.error("[setPolicy] error saving policy: %r" % exx) log.error("[setPolicy] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.debug("[setPolicy] done") ########################################################
[docs] def policies_flexi(self): ''' This function is used to fill the policies tab Unlike the complex /system/getPolcies function, it only returns a simple array of the tokens. ''' pol = {} try: param = getLowerParams(request.params) log.debug("[policies_flexi] viewing policies with params: %r" % param) name = getParam(param, "name", optional) realm = getParam(param, "realm", optional) scope = getParam(param, "scope", optional) sortname = getParam(param, "sortname", optional) sortorder = getParam(param, "sortorder", optional) log.debug("[policies_flexi] retrieving policy name: %s, realm: %s, scope: %s, sort:%s by %s" % (name, realm, scope, sortorder, sortname)) pols = getPolicy({'name':name, 'realm':realm, 'scope': scope}, display_inactive=True) lines = [] for pol in pols: lines.append( { 'id' : pol, 'cell': [ 1 if pols[pol].get('active', "True") == "True" else 0, pol, pols[pol].get('user', ""), pols[pol].get('scope', ""), escape(pols[pol].get('action', "") or ""), pols[pol].get('realm', ""), pols[pol].get('client', ""), pols[pol].get('time', "") ] } ) # sorting reverse = False sortnames = { 'active': 0, 'name' : 1, 'user' : 2, 'scope' : 3, 'action' : 4, 'realm' : 5, 'client':6, 'time' : 7 } if sortorder == "desc": reverse = True lines = sorted(lines, key=lambda policy: policy['cell'][sortnames[sortname]] , reverse=reverse) # end: sorting # We need to return 'page', 'total', 'rows' res = { "page": 1, "total": len(lines), "rows": lines } c.audit['success'] = True c.audit['info'] = "name = %s, realm = %s, scope = %s" % (name, realm, scope) Session.commit() response.content_type = 'application/json' return json.dumps(res, indent=3) except Exception as exx: log.error("[policies_flexi] error in policy flexi: %r" % exx) log.error("[policies_flexi] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.debug("[policies_flexi] done") ########################################################
[docs] def getPolicyDef(self): ''' method: system/getPolicyDef description: This is a helper function that returns the POSSIBLE policy definitions, that can be used to define your policies. arguments: scope - optional - if given, the function will only return policy definitions for the given scope. returns: the policy definitions of - allowed scopes - allowed actions in scopes - type of actions exception: if an error occurs an exception is serialized and returned ''' pol = {} try: param = getLowerParams(request.params) log.debug("[getPolicy] getting policy definitions: %r" % param) scope = getParam(param, "scope", optional) pol = getPolicyDefinitions(scope) dynpol = self._add_dynamic_tokens(scope) pol.update(dynpol) c.audit['success'] = True c.audit['info'] = scope Session.commit() return sendResult(response, pol, 1) except Exception as exx: log.error("[getPolicyDef] error getting policy definitions: %r" % exx) log.error("[getPolicyDef] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.debug("[getPolicyDef] done") #########################################################
def _add_dynamic_tokens(self, scope): ''' add the policy description of the dynamic token :param scope: scope of the policy definition :type scope: string :return: policy dict :rtype: dict ''' pol = {} log.debug("[_add_dynamic_tokens]") glo = config['pylons.app_globals'] tokenclasses = glo.tokenclasses for tok in tokenclasses.keys(): tclass = tokenclasses.get(tok) tclass_object = newToken(tclass) if hasattr(tclass_object, 'getClassInfo'): ## check if we have a policy in the definition try: policy = tclass_object.getClassInfo('policy', ret=None) if policy is not None and policy.has_key(scope): scope_policy = policy.get(scope) pol.update(scope_policy) except Exception as exx: log.info('[dynamicToken] no policy for tokentype %r found (%r)' % (tok, exx)) return pol #########################################################
[docs] def importPolicy(self): ''' method: system/importPolicy description: This function is used to import policies from a file. arguments: file - mandatory: The policy file in the POST request ''' sendResultMethod = sendResult sendErrorMethod = sendError res = True try: log.debug("[importPolicy] getting POST request: %r" % request.POST) policy_file = request.POST['file'] fileString = "" log.debug("[importPolicy] loading policy file to server using POST request. File: %s" % policy_file) # In case of form post requests, it is a "instance" of FieldStorage # i.e. the Filename is selected in the browser and the data is transferred # in an iframe. see: http://jquery.malsup.com/form/#sample4 # if type(policy_file).__name__ == 'instance': log.debug("[importPolicy] Field storage file: %s", policy_file) fileString = policy_file.value sendResultMethod = sendXMLResult sendErrorMethod = sendXMLError else: fileString = policy_file log.debug("[importPolicy] fileString: %s", fileString) if fileString == "": log.error("[importPolicy] Error loading/importing policy file. file empty!") return sendErrorMethod(response, "Error loading policy. File empty!") # the contents of filestring needs to be parsed and stored as policies. from configobj import ConfigObj policies = ConfigObj(fileString.split('\n'), encoding="UTF-8") log.info("[importPolicy] read the following policies: %s" % policies) res = len(policies) for policy_name in policies.keys(): ret = setPolicy({ 'name': policy_name, 'action' : policies[policy_name].get('action', ""), 'scope' : policies[policy_name].get('scope', ""), 'realm' : policies[policy_name].get('realm', ""), 'user' : policies[policy_name].get('user', ""), 'time' : policies[policy_name].get('time', ""), 'client': policies[policy_name].get('client', "")}) log.debug("[importPolicy] import policy %s: %s" % (policy_name, ret)) c.audit['info'] = "Policies imported from file %s" % policy_file c.audit['success'] = 1 Session.commit() return sendResultMethod(response, res) except Exception as exx: log.error("[importPolicy] failed! %r" % exx) log.error("[importPolicy] %s" % traceback.format_exc()) Session.rollback() return sendErrorMethod(response, exx) finally: Session.close() log.error("[importPolicy] done") ############################################################
[docs] def checkPolicy(self): ''' method: system/checkPolicy description: this function checks if a the given parameter will trigger a policy or not. arguments: * user - the name of the user * realm - the realm * scope - the scope * action * client - the client IP returns: a json result like this: value : { "allowed" : "true", "policy" : <Name der Policy, die das erlaubt hat> } value : { "allowed" : "false", "info" : <sowas wie die Fehlermeldung> } ''' res = {} try: param = getLowerParams(request.params) user = getParam(param, "user", required) realm = getParam(param, "realm", required) scope = getParam(param, "scope", required) action = getParam(param, "action", required) client = getParam(param, "client", required) pol = {} if scope in ["admin", "system"]: pol = getPolicy({"scope":scope}) log.debug("CKO %s" % pol) if len(pol) > 0: # Policy active for this scope! pol = getPolicy({"user":user, "realm":realm, "scope":scope, "action":action, "client":client}) res["allowed"] = len(pol) > 0 res["policy"] = pol if len(pol) > 0: c.audit['info'] = "allowed by policy %s" % pol.keys() else: # No policy active for this scope c.audit['info'] = "allowed since no policies in scope %s" % scope res["allowed"] = True res["policy"] = "No policies in scope %s" % scope else: log.debug("[checkPolicy] checking policy for client %s, scope %s, action %s, realm %s and user %s" % (client, scope, action, realm, user)) pol = get_client_policy(client, scope, action, realm, user) res["allowed"] = len(pol) > 0 res["policy"] = pol if len(pol) > 0: c.audit['info'] = "allowed by policy %s" % pol.keys() c.audit['action_detail'] = "action = %s, realm = %s, scope = %s"\ % (action, realm, scope) c.audit['success'] = True Session.commit() return sendResult(response, res, 1) except Exception as exx: log.error("[checkPolicy] error checking policy: %r" % exx) log.error("[checkPolicy] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.error("[checkPolicy] done") ##########################################################################
[docs] def getPolicy(self): """ method: system/getPolicy description: this function is used to retrieve the policies that you defined. arguments: * realm - (optional) will return all policies in the given realm * name - (optional) will only return the policy with the given name * scope - (optional) will only return the policies within the given scope * export - (optional) The filename needs to be specified as the third part of the URL like /system/getPolicy/policy.cfg. It will then be exported to this file. * display_inactive - (optional) if set, then also inactive policies will be displayed returns: a json result with the configuration of the specified policies exception: if an error occurs an exception is serialized and returned """ pol = {} param = getLowerParams(request.params) log.debug("[getPolicy] getting policy: %r" % param) export = None ### config settings from here try: name = getParam(param, "name", optional) realm = getParam(param, "realm", optional) scope = getParam(param, "scope", optional) display_inactive = getParam(param, "display_inactive", optional) if display_inactive: display_inactive = True route_dict = request.environ.get('pylons.routes_dict') export = route_dict.get('id') log.debug("[getPolicy] retrieving policy name: %s, realm: %s, scope: %s" % (name, realm, scope)) pol = {} if name != None: for nam in name.split(','): poli = getPolicy({'name':nam, 'realm':realm, 'scope': scope}, display_inactive=display_inactive) pol.update(poli) else: pol = getPolicy({'name':name, 'realm':realm, 'scope': scope}, display_inactive=display_inactive) c.audit['success'] = True c.audit['info'] = "name = %s, realm = %s, scope = %s" \ % (name, realm, scope) Session.commit() if export: filename = create_policy_export_file(pol, export) wsgi_app = FileApp(filename) return wsgi_app(request.environ, self.start_response) else: return sendResult(response, pol, 1) except Exception as exx: log.error("[getPolicy] error getting policy: %r" % exx) log.error("[getPolicy] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.error("[getPolicy] done") ########################################################
[docs] def delPolicy(self): """ method: system/delPolicy description: this function deletes the policy with the given name arguments: name - the policy with the given name returns: a json result about the delete success exception: if an error occurs an exception is serialized and returned """ res = {} try: param = getLowerParams(request.params) log.info("[delPolicy] deleting policy: %r" % param) name = getParam(param, "name", required) log.debug("[delPolicy] trying to delete policy %s" % name) ret = deletePolicy(name) res["delPolicy"] = {"result": ret} c.audit['success'] = ret c.audit['info'] = name Session.commit() return sendResult(response, res, 1) except Exception as exx: log.error("[delPolicy] error deleting policy: %r" % exx) log.error("[delPolicy] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.error("[delPolicy] done") ########################################################
def setupSecurityModule(self): res = {} try: params = getLowerParams(request.params) log.debug("[setupSecurityModule] parameters: %r" % params) log.debug("[setupSecurityModule] : start setup") hsm_id = params.get('hsm_id', None) from linotp.lib.config import getGlobalObject glo = getGlobalObject() sep = glo.security_provider ## for test purpose we switch to an errHSM if isSelfTest(): if params.get('__hsmexception__') == '__ON__': hsm = c.hsm.get('obj') hsm_id = sep.activeOne if type(hsm).__name__ == 'DefaultSecurityModule': hsm_id = sep.setupModule('err', params) if params.get('__hsmexception__') == '__OFF__': hsm = c.hsm.get('obj') hsm_id = sep.activeOne if type(hsm).__name__ == 'ErrSecurityModule': hsm_id = sep.setupModule('default', params) if hsm_id is None: hsm_id = sep.activeOne hsm = c.hsm.get('obj') error = c.hsm.get('error') if hsm is None or len(error) != 0: raise Exception ('current activeSecurityModule >%r< is not initialized::%s:: - Please check your security module configuration and connection!' % (hsm_id, error)) ready = hsm.isReady() res['setupSecurityModule'] = {'activeSecurityModule': hsm_id , 'connected' : ready } ret = ready else: if hsm_id != sep.activeOne: raise Exception ('current activeSecurityModule >%r< could only be changed through the configuration!' % sep.activeOne) ret = sep.setupModule(hsm_id, config=params) hsm = c.hsm.get('obj') ready = hsm.isReady() res['setupSecurityModule'] = {'activeSecurityModule': hsm_id , 'connected' : ready , 'result' : ret} c.audit['success'] = ret Session.commit() return sendResult(response, res, 1) except Exception as exx: log.error("[setupSecurityModule] : setup failed: %r" % exx) log.error("[setupSecurityModule] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.error("[setupSecurityModule] done") ########################################################
[docs] def getSupportInfo(self): """ return the support status, which is community support by default or the support subscription info, which could be the old license """ res = {} params = {} try: params.update(request.params) log.debug("[getSupportInfo] parameters: %r" % params) license_data = getFromConfig("license") if license_data is not None and len(license_data) > 0: support_string = binascii.unhexlify(license_data) (support_info, sign, licStr) = parseSubscription(support_string) res['description'] = support_info else: version = get_version_number() support_info = {} support_info['comment'] = (_('LinOTP Support Info')) support_info['version'] = 'LinOTP %s' % version support_info['issuer'] = '' support_info['token-num'] = '' support_info['licensee'] = '' support_info['address'] = '<a href="http://www.lsexperts.de" target="_blank">http://www.lsexperts.de</a>' support_info['contact-name'] = '' support_info['contact-email'] = '<a href="mailto:linotp@lsexperts.de">linotp@lsexperts.de</a>' support_info['contact-phone'] = '+49 6151 86086-115' support_info['date'] = '' support_info['expire'] = '' support_info['subscription'] = ( _('You are using the open source version with community ' 'support. For professional support, feel free to contact ' 'LSE by email or by phone.')) res['description'] = support_info c.audit['success'] = res Session.commit() return sendResult(response, res, 1) except Exception as exx: log.error("[getSupportInfo] : failed to access support info: %r" % exx) log.error("[getSupportInfo] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.error("[getSupportInfo] done")
[docs] def setSupport(self): """ hook to load a support subscription file receives the data with a form post file upload """ res = False params = {} support_description = "" try: licField = request.POST['license'] log.info("[setSupport] setting support: %s" % (licField)) # In case of normal post requests, it is a "instance" of FieldStorage if type(licField).__name__ == 'instance': log.debug("[setSupport] Field storage: %s", licField) support_description = licField.value else: # we got UTF-8! support_description = licField.encode('utf-8') log.debug("[setSupport] license %s", support_description) storeConfig("license", binascii.hexlify(support_description)) res = True c.audit['success'] = res Session.commit() return sendResult(response, res, 1) except Exception as exx: log.error("[setSupport] : failed to acces support info: %r" % exx) log.error("[setSupport] %s" % traceback.format_exc()) Session.rollback() return sendError(response, exx) finally: Session.close() log.error("[setSupport] done") return valid; ### helper function
def parseSubscription(licString): """ parse the support subscription license :param licString: the support license as multiline string :return: tuple of license dict, extracted signature and the license as string, which the signature could be checked against """ licInfo = {} signature = "" licStr = "" read_license = 0 read_signature = 0 for l in licString.split('\n'): if (l.startswith("-----BEGIN LICENSE-----")): read_license = 1 elif (l.startswith("-----END LICENSE-----")): read_license = 0 elif (l.startswith("-----BEGIN LICENSE SIGNATURE-----")): read_signature = 1 elif (l.startswith("-----END LICENSE SIGNATURE-----")): read_signature = 0 else: if 1 == read_license: licStr = licStr + l + "\n" try: (key, val) = l.split("=", 2) licInfo[key] = val except: log.debug("->parseLicense - %s", l) if 1 == read_signature: signature += l.rstrip() log.debug("->p - :::%s:::", licStr) return (licInfo, signature, licStr) #eof###########################################################################