"Fossies" - the Fresh Open Source Software Archive

Member "LinOTP-release-2.10.5.3/linotpd/src/linotp/lib/config/config_class.py" (24 Jun 2019, 11836 Bytes) of package /linux/misc/LinOTP-release-2.10.5.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "config_class.py" see the Fossies "Dox" file reference documentation.

    1 # -*- coding: utf-8 -*-
    2 #
    3 #    LinOTP - the open source solution for two factor authentication
    4 #    Copyright (C) 2010 - 2019 KeyIdentity GmbH
    5 #
    6 #    This file is part of LinOTP server.
    7 #
    8 #    This program is free software: you can redistribute it and/or
    9 #    modify it under the terms of the GNU Affero General Public
   10 #    License, version 3, as published by the Free Software Foundation.
   11 #
   12 #    This program is distributed in the hope that it will be useful,
   13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
   14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15 #    GNU Affero General Public License for more details.
   16 #
   17 #    You should have received a copy of the
   18 #               GNU Affero General Public License
   19 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   20 #
   21 #
   22 #    E-mail: linotp@keyidentity.com
   23 #    Contact: www.linotp.org
   24 #    Support: www.keyidentity.com
   25 #
   26 """
   27     handle all configuration items with aspekts like persitance and
   28        syncronysation and provides this to all requests
   29 """
   30 
   31 import logging
   32 import os
   33 import time
   34 
   35 from datetime import datetime
   36 
   37 from linotp.config import environment as env
   38 from linotp.lib.config.util import expand_here
   39 
   40 from linotp.lib.config.db_api import _removeConfigDB
   41 from linotp.lib.config.db_api import _retrieveAllConfigDB
   42 from linotp.lib.config.db_api import _storeConfigDB
   43 from linotp.lib.config.db_api import _retrieveConfigDB
   44 
   45 from linotp.lib.config.global_api import getGlobalObject
   46 from linotp.lib.config.global_api import _getConfigReadLock
   47 from linotp.lib.config.global_api import _releaseConfigLock
   48 
   49 from linotp.lib.config.type_definition import Config_Types
   50 
   51 """
   52     LinOTP Config class
   53     - a dictionary to hold the config entries with a backend database
   54 """
   55 
   56 log = logging.getLogger(__name__)
   57 
   58 
   59 class LinOtpConfig(dict):
   60     """
   61     This class should be a request singleton.
   62 
   63     In case of a change, it must cover the different aspects like
   64 
   65     - env config entry
   66     - and app_globals
   67     - and finally sync this to disc
   68 
   69     """
   70 
   71     def __init__(self, *args, **kw):
   72         self.parent = super(LinOtpConfig, self)
   73         self.parent.__init__(*args, **kw)
   74 
   75         self.delay = False
   76         self.realms = None
   77         self.glo = getGlobalObject()
   78         conf = self.glo.getConfig()
   79 
   80         do_reload = False
   81 
   82         # do the bootstrap if no entry in the app_globals
   83         if len(conf.keys()) == 0:
   84             do_reload = True
   85 
   86         if self.glo.isConfigComplet() is False:
   87             do_reload = True
   88             self.delay = True
   89 
   90         if 'linotp.enableReplication' in conf:
   91             val = conf.get('linotp.enableReplication')
   92             if val.lower() == 'true':
   93 
   94                 # look for the timestamp when config was created
   95                 e_conf_date = conf.get('linotp.Config')
   96 
   97                 # in case of replication, we always have to look if the
   98                 # config data in the database changed
   99                 db_conf_date = _retrieveConfigDB('linotp.Config')
  100 
  101                 if str(db_conf_date) != str(e_conf_date):
  102                     do_reload = True
  103 
  104         self.refreshConfig(do_reload=do_reload)
  105 
  106         return
  107 
  108     def refreshConfig(self, do_reload=False):
  109 
  110         conf = self.glo.getConfig()
  111 
  112         if do_reload is True:
  113             # in case there is no entry in the dbconf or
  114             # the config file is newer, we write the config back to the db
  115             entries = conf.keys()
  116             for entry in entries:
  117                 del conf[entry]
  118 
  119             writeback = False
  120             # get all conf entries from the config file
  121             fileconf = _getConfigFromEnv()
  122 
  123             # get all configs from the DB
  124             (dbconf, delay) = _retrieveAllConfigDB()
  125             self.glo.setConfigIncomplete(not delay)
  126 
  127             # we only merge the config file once as a removed entry
  128             #  might reappear otherwise
  129             if 'linotp.Config' not in dbconf:
  130                 conf.update(fileconf)
  131                 writeback = True
  132 
  133             conf.update(dbconf)
  134             # check, if there is a selfTest in the DB and delete it
  135             if 'linotp.selfTest' in dbconf:
  136                 _removeConfigDB('linotp.selfTest')
  137                 _storeConfigDB('linotp.Config', datetime.now())
  138 
  139             # the only thing we take from the fileconf is the selftest
  140             if 'linotp.selfTest' in fileconf:
  141                 conf['linotp.selfTest'] = 'True'
  142 
  143             if writeback is True:
  144                 for con in conf:
  145                     if con != 'linotp.selfTest':
  146                         _storeConfigDB(con, conf.get(con))
  147                 _storeConfigDB(u'linotp.Config', datetime.now())
  148 
  149             self.glo.setConfig(conf, replace=True)
  150 
  151         self.parent.update(conf)
  152         return
  153 
  154     def setRealms(self, realmDict):
  155         self.realms = realmDict
  156         return
  157 
  158     def getRealms(self):
  159         return self.realms
  160 
  161     def addEntry(self, key, val, typ=None, des=None):
  162         '''
  163         small wrapper, as the assignement opperator has only one value argument
  164 
  165         :param key: key of the dict
  166         :type  key: string
  167         :param val: any value, which is put in the dict
  168         :type  val: any type
  169         :param typ: used in the database to control if the data is encrypted
  170         :type  typ: None,string,password
  171         :param des: literal, which describes the data
  172         :type  des: string
  173         '''
  174         if not key.startswith('linotp.'):
  175             key = 'linotp.' + key
  176 
  177         return self.__setitem__(key, val, typ, des)
  178 
  179     def __setitem__(self, key, val, typ=None, des=None):
  180         '''
  181         implemtation of the assignement operator == internal function
  182 
  183         :param key: key of the dict
  184         :type  key: string
  185         :param val: any value, which is put in the dict
  186         :type  val: any type
  187         :param typ: used in the database to control if the data is encrypted
  188         :type  typ: None,string,password
  189         :param des: literal, which describes the data
  190         :type  des: string
  191         '''
  192 
  193         # do some simple typing for known config entries
  194         self._check_type(key, val)
  195 
  196         nVal = expand_here(val)
  197 
  198         # update this config and sync with global dict and db
  199 
  200         res = self.parent.__setitem__(key, nVal)
  201         self.glo.setConfig({key: nVal})
  202 
  203         # ----------------------------------------------------------------- --
  204 
  205         # finally store the entry in the database and
  206         # syncronize as well the global timestamp
  207 
  208         now = datetime.now()
  209 
  210         self.glo.setConfig({'linotp.Config': unicode(now)})
  211 
  212         _storeConfigDB(key, val, typ, des)
  213         _storeConfigDB('linotp.Config', now)
  214 
  215         return res
  216 
  217     def _check_type(self, key, value):
  218         """
  219         check if we have a type description for this entry:
  220         - if so, we take the tuple of type 'as literal' and
  221           the type check function, we are running against the given value
  222 
  223         :param key: the to be stored key
  224         :param value: the to be stored value
  225 
  226         :return: - nothing -
  227         :raises: ValueError - if value is not type compliant
  228 
  229         """
  230 
  231         if key in Config_Types:
  232 
  233             #
  234             # get the tuple of type as literal and type checking function
  235             #
  236 
  237             typ, check_type_function = Config_Types[key]
  238 
  239             if not check_type_function(value):
  240                 raise ValueError("Config Error: %s must be of type %r" %
  241                                  (key, typ))
  242 
  243     def get(self, key, default=None):
  244         '''
  245             check for a key in the linotp config
  246 
  247             remark: the config entries all start with linotp.
  248             if a key is not found, we do a check if there is
  249             a linotp. prefix set in the key and potetialy prepend it
  250 
  251             :param key: search value
  252             :type  key: string
  253             :param default: default value, which is returned,
  254                             if the value is not found
  255             :type  default: any type
  256 
  257             :return: value or None
  258             :rtype:  any type
  259         '''
  260         # has_key is required here, as we operate on the dict class
  261 
  262         if not self.parent.has_key(key) and not key.startswith('linotp.'):
  263             key = 'linotp.' + key
  264 
  265         # return default only if key does not exist
  266         res = self.parent.get(key, default)
  267         return res
  268 
  269     def has_key(self, key):
  270         res = self.parent.has_key(key)
  271         if res is False and key.startswith('linotp.') is False:
  272             key = 'linotp.' + key
  273 
  274         res = self.parent.has_key(key)
  275 
  276         if res is False and key.startswith('enclinotp.') is False:
  277             key = 'enclinotp.' + key
  278 
  279         res = self.parent.has_key(key)
  280 
  281         return res
  282 
  283     def __delitem__(self, key):
  284         '''
  285         remove an item from the config
  286 
  287         :param key: the name of the ocnfig entry
  288         :type  key: string
  289 
  290         :return : return the std value like the std dict does, whatever this is
  291         :rtype  : any value a dict update will return
  292         '''
  293         Key = key
  294 
  295         if self.parent.has_key(key):
  296             Key = key
  297 
  298         elif self.parent.has_key('linotp.' + key):
  299             Key = 'linotp.' + key
  300 
  301         res = self.parent.__delitem__(Key)
  302 
  303         # sync with global dict
  304 
  305         self.glo.delConfig(Key)
  306 
  307         # sync with db
  308         if key.startswith('linotp.'):
  309             Key = key
  310         else:
  311             Key = 'linotp.' + key
  312 
  313         _removeConfigDB(Key)
  314         _storeConfigDB('linotp.Config', datetime.now())
  315 
  316         return res
  317 
  318     def __contains__(self, key):
  319         """
  320         support for 'in' operator of the Config dict
  321         """
  322         res = (self.parent.__contains__(key) or
  323                self.parent.__contains__('linotp.' + key))
  324         return res
  325 
  326     def update(self, dic):
  327         '''
  328         update the config dict with multiple items in a dict
  329 
  330         :param dic: dictionary of multiple items
  331         :type  dic: dict
  332 
  333         :return : return the std value like the std dict does, whatever this is
  334         :rtype  : any value a dict update will return
  335         '''
  336 
  337         #
  338         # first check if all data is type compliant
  339         #
  340 
  341         for key, val in dic.items():
  342             self._check_type(key, val)
  343 
  344         #
  345         # put the data in the parent dictionary
  346         #
  347 
  348         res = self.parent.update(dic)
  349 
  350         #
  351         # and sync the data with the global config dict
  352         #
  353 
  354         self.glo.setConfig(dic)
  355 
  356         #
  357         # finally sync the entries to the database
  358         #
  359 
  360         for key in dic:
  361             if key != 'linotp.Config':
  362                 _storeConfigDB(key, dic.get(key))
  363 
  364         _storeConfigDB('linotp.Config', datetime.now())
  365         return res
  366 
  367 
  368 ###############################################################################
  369 #  helper class from here
  370 ###############################################################################
  371 
  372 def _getConfigFromEnv():
  373 
  374     linotpConfig = {}
  375 
  376     try:
  377         _getConfigReadLock()
  378         for entry in env.config:
  379             # we check for the modification time of the config file
  380             if entry == '__file__':
  381                 fname = env.config.get('__file__')
  382                 mTime = time.localtime(os.path.getmtime(fname))
  383                 modTime = datetime(*mTime[:6])
  384                 linotpConfig['linotp.Config'] = modTime
  385 
  386             if entry.startswith("linotp."):
  387                 linotpConfig[entry] = expand_here(env.config[entry])
  388             if entry.startswith("enclinotp."):
  389                 linotpConfig[entry] = env.config[entry]
  390         _releaseConfigLock()
  391     except Exception as e:
  392         log.exception('Error while reading config: %r' % e)
  393         _releaseConfigLock()
  394     return linotpConfig
  395 
  396 
  397 # eof #