Esempio n. 1
0
class MachineController(BaseController):

    @log_with(log)
    def __before__(self, action, **params):
        '''
        '''
        try:
            c.audit['success'] = False
            c.audit['client'] = get_client()
            self.Policy = PolicyClass(request, config, c,
                                      get_privacyIDEA_config(),
                                      tokenrealms=request.params.get('serial'),
                                      token_type_list=get_token_type_list())
            self.set_language()

            self.before_identity_check(action)

            Session.commit()
            return request

        except webob.exc.HTTPUnauthorized as acc:
            # the exception, when an abort() is called if forwarded
            log.info("%r: webob.exception %r" % (action, acc))
            log.info(traceback.format_exc())
            Session.rollback()
            Session.close()
            raise acc

        except Exception as exx:
            log.error("exception %r" % (action, exx))
            log.error(traceback.format_exc())
            Session.rollback()
            Session.close()
            return sendError(response, exx, context='before')

        finally:
            pass

    @log_with(log)
    def __after__(self, action, **params):
        '''
        '''
        params = {}

        try:
            params.update(request.params)
            c.audit['administrator'] = getUserFromRequest(request).get("login")
            if 'serial' in params:
                    c.audit['serial'] = request.params['serial']
                    c.audit['token_type'] = getTokenType(params.get('serial'))

            self.audit.log(c.audit)

            Session.commit()
            return request

        except Exception as e:
            log.error("unable to create a session cookie: %r" % e)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, e, context='after')

        finally:
            Session.close()

    @log_with(log)
    def create(self, action, **params):
        '''
        Create a new client machine entry

        :param name: the unique name of the machine (required). Can be the FQDN.
        :param desc: description of the machine
        :param ip: The IP address of the machine
        :param decommission: A date when the machine will not be valid anymore

        :return: True or False if the creation was successful.
        '''
        try:
            res = False
            param = {}
            # check machine authorization
            self.Policy.checkPolicyPre('machine', 'create')

            param.update(request.params)
            machine_name = getParam(param, "name", required)
            ip = getParam(param, "ip", optional)
            desc = getParam(param, "desc", optional)
            decommission = getParam(param, "decommission", optional)
            machine = create_machine(machine_name, 
                                     ip=ip, 
                                     desc=desc, 
                                     decommission=decommission)
            if machine:
                res = True 
            Session.commit()
            c.audit["success"] = True
            return sendResult(response, res, 1)

        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:
            log.error("failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(exx), 0)

        finally:
            Session.close()
            
    @log_with(log)
    def delete(self, action, **params):
        '''
        Delete an existing client machine entry
        
        :param name: the unique name of the machine
        
        :return: value is either true (success) or false (fail)
        '''
        try:
            res = {}
            param = {}
            # check machine authorization
            self.Policy.checkPolicyPre('machine', 'delete')
            param.update(request.params)
            machine_name = getParam(param, "name", required)
            res = delete_machine(machine_name)
            Session.commit()
            c.audit["success"] = True
            return sendResult(response, res, 1)

        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:
            log.error("failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(exx), 0)

        finally:
            Session.close()

    @log_with(log)
    def show(self, action, **params):
        '''
        Returns a list of the client machines.
        
        :param name: Optional parameter to only show this single machine
        
        :return: JSON details
        '''
        try:
            res = {}
            param = {}
            # check machine authorization
            self.Policy.checkPolicyPre('machine', 'show')
            param.update(request.params)
            machine_name = getParam(param, "name", optional)
            
            res = show_machine(machine_name)
            Session.commit()
            c.audit["success"] = True
            return sendResult(response, res, 1)

        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:
            log.error("failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(exx), 0)

        finally:
            Session.close()

    @log_with(log)
    def addtoken(self, action, **params):
        '''
        Add a token and a application to a machine
        
        :param name: Name of the machine
        :param serial: serial number of the token
        :param application: name of the application
        '''
        try:
            res = False
            param = {}
            # check machine authorization
            self.Policy.checkPolicyPre('machine', 'addtoken')
            param.update(request.params)
            machine_name = getParam(param, "name", required)
            serial = getParam(param, "serial", required)
            application = getParam(param, "application", required)
            
            if application.lower() not in config.get("applications").keys():
                log.error("Unknown application %r. Available applications: "
                          "%r" % (application, config.get("applications").keys()))
                raise Exception("Unkown application!")
            
            mt = addtoken(machine_name, serial, application)
            if mt:
                res = True
            Session.commit()
            c.audit["success"] = True
            return sendResult(response, res, 1)

        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:
            log.error("failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(exx), 0)

        finally:
            Session.close()
        
    @log_with(log)
    def deltoken(self, action, **params):
        '''
        delete a token and a application from a machine
        
        :param name: Name of the machine
        :param serial: serial number of the token
        :param application: name of the application
        '''
        try:
            res = False
            param = {}
            # check machine authorization
            self.Policy.checkPolicyPre('machine', 'deltoken')
            param.update(request.params)
            machine_name = getParam(param, "name", required)
            serial = getParam(param, "serial", required)
            application = getParam(param, "application", required)
            
            res = deltoken(machine_name, serial, application)
            Session.commit()
            c.audit["success"] = True
            return sendResult(response, res, 1)

        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:
            log.error("failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(exx), 0)

    @log_with(log)
    def showtoken(self, action, **params):
        '''
        show a token and a application from a machine
        
        :param name: Name of the machine
        :param serial: serial number of the token
        :param application: name of the application
        :param flexi: if set to 1, we do return flexigrid input
        '''
        try:
            res = False
            param = {}
            # check machine authorization
            self.Policy.checkPolicyPre('machine', 'showtoken')
            param.update(request.params)
            machine_name = getParam(param, "name", optional)
            serial = getParam(param, "serial", optional)
            application = getParam(param, "application", optional)
            # if set, this should be returned for flexigrid
            flexi = getParam(param, "flexi", optional)

            res = showtoken(machine_name,
                            serial,
                            application,
                            flexi=flexi,
                            params=param)
            Session.commit()
            c.audit["success"] = True
            if flexi:
                response.content_type = 'application/json'
                return json.dumps(res, indent=3)
            else:
                return sendResult(response, res, 1)

        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:
            log.error("failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(exx), 0)

        finally:
            Session.close()

    @log_with(log)
    def gettokenapps(self, action, **params):
        '''
        returns the apps and the authentication information
        for the given machine.

        If an application is given only the authentication item for
        this application is returned. otherwise the application items
        for all applications are returned.

        TODO: Authenticate the client machine

        :param name: the machine name -
                    otherwise the machine is identified by the IP
        :type name: string, optional
        :param application: the name of the application
        :type application: sting, optional
        :param serial: THe serial number of the token
        '''
        try:
            res = False
            param = {}
            self.Policy.checkPolicyPre('machine', 'gettokenapps')
            param.update(request.params)
            machine_name = getParam(param, "name", optional)
            application = getParam(param, "application", optional)
            serial = getParam(param, "serial", optional)
            challenge = None
            if isSelfTest():
                challenge = getParam(param, "challenge", optional)
            client_ip = get_client()
            
            if application:
                if application not in config.get("applications").keys():
                    log.error("Unknown application %r. Available applications: "
                              "%r" % (application, config.get("applications").keys()))
            application_module = config.get("applications").get(application)
            
            res = get_token_apps(machine=machine_name,
                                 application=application,
                                 application_module=application_module,
                                 serial=serial,
                                 client_ip=client_ip,
                                 challenge=challenge)
            Session.commit()
            c.audit["success"] = True
            return sendResult(response, res, 1)

        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:
            log.error("failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(exx), 0)

        finally:
            Session.close()
        
    @log_with(log)
    def getapplications(self, action, **params):
        '''
        Returns a list of available applications
        '''
        try:
            return sendResult(response, config.get("applications").keys())
        
        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:
            log.error("failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(exx), 0)

        finally:
            Session.close()
Esempio n. 2
0
    def search(self, action, **params):

        '''
        This functions searches within the audit trail
        It returns the audit information for the given search pattern

        method:
            audit/search

        arguments:
            key, value pairs as search patterns.

            * outform - optional: if set to "csv", than the token list will be
                        given in CSV


            or: Usually the key=values will be locally AND concatenated.
                it a parameter or=true is passed, the filters will
                be OR concatenated.

            The Flexigrid provides us the following parameters:
                ('page', u'1'), ('rp', u'100'),
                ('sortname', u'number'),
                ('sortorder', u'asc'),
                ('query', u''), ('qtype', u'serial')]
        returns:
            JSON response or csv format
        '''

        param = {}
        try:
            param.update(request.params)

            output_format = getParam(param, "outform", optional)
            Policy = PolicyClass(request, config, c,
                                 get_privacyIDEA_config(),
                                 token_type_list=get_token_type_list())
            Policy.checkPolicyPre('audit', 'view', {})

            # remove the param outform (and other parameters that should not
            # be used for search!
            search_params = {}
            for p in param:
                if p not in ["outform"]:
                    search_params[p] = param[p]

            log.debug("search params %r" % search_params)

            audit_iter = None

            if output_format == "csv":
                filename = "privacyidea-audit.csv"
                response.content_type = "application/force-download"
                response.headers['Content-'
                                 'disposition'] = ('attachment; filename=%s'
                                                   % filename)
                audit_iter = CSVAuditIterator(search_params)
            else:
                response.content_type = 'application/json'
                audit_iter = JSONAuditIterator(search_params)

            c.audit['success'] = True
            Session.commit()
            return audit_iter

        except PolicyException as pe:
            log.error("gettoken/getotp policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe), 1)

        except Exception as e:
            log.error("audit/search failed: %r" % e)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response,
                             "audit/search failed: %s" % unicode(e), 0)

        finally:
            Session.close()
Esempio n. 3
0
class SystemController(BaseController):

    '''
    The privacyidea.controllers are the implementation of the web-API to talk to the privacyIDEA server.
    The SystemController is used to configure the privacyIDEA server.
    The functions of the SystemController are invoked like this

        https://server/system/<functionname>

    The functions are described below in more detail.
    '''

    @log_with(log)
    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
        '''
        try:
            c.audit['success'] = False
            c.audit['client'] = get_client()
            self.Policy = PolicyClass(request, config, c,
                                      get_privacyIDEA_config(),
                                      token_type_list = get_token_type_list())
            self.before_identity_check(action)
            
            # check authorization
            if action not in ["_add_dynamic_tokens", 'setupSecurityModule',]:
                self.Policy.checkPolicyPre('system', action)

            ## default return for the __before__ and __after__
            return response

        except PolicyException as pex:
            log.error("%r: policy exception %r" % (action, pex))
            log.error(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("%r: webob.exception %r" % (action, acc))
            log.error(traceback.format_exc())
            Session.rollback()
            Session.close()
            raise acc

        except Exception as exx:
            log.error("%r: exception %r" % (action, exx))
            log.error(traceback.format_exc())
            Session.rollback()
            Session.close()
            return sendError(response, exx, context='before')

        finally:
            pass


    @log_with(log)
    def __after__(self, action, **params):
        '''
        __after is called after every action

        :return: return the response
        :rtype:  pylons response
        '''
        try:
            c.audit['administrator'] = getUserFromRequest(request).get("login")
            self.audit.log(c.audit)
            ## default return for the __before__ and __after__
            return response

        except Exception as exx:
            log.error("exception %r" % (exx))
            log.error(traceback.format_exc())
            Session.rollback()
            Session.close()
            return sendError(response, exx, context='after')

        finally:
            pass


########################################################

    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)

            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("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('commit failed: %r' % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, exx)

        finally:
            Session.close()


########################################################
    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.

        *remark: 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)
            if "key" in param:

                key = param.get("key")
                val = param.get("value", None)
                typ = param.get("type", None)
                des = param.get("description", None)

                if val is None:
                    raise ParameterError("Required parameters: value")

                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 remove_session_from_param(param):
                    val = param.get(key, '') or ''

                    Key = key
                    if not key.startswith('privacyidea'):
                        Key = 'privacyidea.' + 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("error saving config: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, exx)

        finally:
            Session.close()

########################################################

    @log_with(log)
    def delConfig(self, action, **params):
        """
        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)

            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("error deleting config: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, exx)

        finally:
            Session.close()


########################################################
########################################################

    @log_with(log)
    def getConfig(self, action, **params):
        """
        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(remove_session_from_param(request.params))

            ## if there is no parameter, we return them all
            if len(param) == 0:
                conf = get_privacyIDEA_config()
                keys = conf.keys()
                keys.sort()
                for key in keys:
                    if key.startswith("encprivacyidea."):
                        continue
                    if key.startswith("privacyidea."):
                        Key = key[len("privacyidea."):]
                        typ = type(conf.get(key)).__name__
                        if typ == 'datetime':
                            res[Key] = unicode(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("encprivacyidea."):
                        Key = key[len("encprivacyidea."):]
                        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("error getting config: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, exx)

        finally:
            Session.close()


########################################################
    @log_with(log)
    def getRealms(self, action, **params):
        '''
        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)
            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 = self.Policy.checkPolicyPost('system', 'getRealms', { 'realms' : res })
            res = polPost['realms']

            Session.commit()
            return sendResult(response, res, 1)

        except PolicyException as pex:
            log.error("policy exception: %r" % pex)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, pex)

        except Exception as exx:
            log.error("error getting realms: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, exx)

        finally:
            Session.close()


########################################################
    @log_with(log)
    def setResolver(self, action, **params):
        """
        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)

            res = defineResolver(param)

            Session.commit()
            return sendResult(response, res, 1)

        except Exception as exx:
            log.error("error saving config: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, exx)

        finally:
            Session.close()


########################################################
    @log_with(log)
    def getResolvers(self, action, **params):
        """
        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:
            res = getResolverList()

            c.audit['success'] = True
            Session.commit()
            return sendResult(response, res, 1)

        except Exception as exx:
            log.error("error getting resolvers: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, exx)

        finally:
            Session.close()


########################################################
    @log_with(log)
    def delResolver(self, action, **params):
        """
        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)

            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:
                    if resolver == get_resolver_name(idRes):
                        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("error deleting resolver: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, exx)

        finally:
            Session.close()


########################################################
    @log_with(log)
    def getResolver(self, action, **params):
        """
        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)

            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("error getting resolver: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, exx)

        finally:
            Session.close()


    @log_with(log)
    def get_resolver_list(self, action, **params):
        res = {}
        try:
            from privacyidea.config.environment import get_resolver_list as getlist
            list = getlist()
            res['resolverlist'] = [l for l in list]
            res['resolvertypes'] = [l.split(".")[-1] for l in list]
            return sendResult(response, res, 1)
        except Exception as exx:
            Session.rollback()
            return sendError(response, exx)
        finally:
            Session.close()

########################################################
    @log_with(log)
    def setDefaultRealm(self, action, **params):
        """
        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)

            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("setting default realm failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, exx)

        finally:
            Session.close()


########################################################
    @log_with(log)
    def getDefaultRealm(self, action, **params):
        """
        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("return default realm failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, exx)

        finally:
            Session.close()


########################################################
    @log_with(log)
    def setRealm(self, action, **params):
        """
        method:
            system/setRealm

        description:
            this function is used to define a realm with the given
            useridresolvers

        arguments:
            realm     - name of the realm
            resolvers - comma seperated 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)

            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 is False:
                    raise Exception("Error in resolver %r please check the"
                                    " logfile!" % 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("%r %r" % (err, exx))
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, exx)

        finally:
            Session.close()


########################################################
    @log_with(log)
    def delRealm(self, action, **params):
        """
        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
            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("")
                # this is a remnant of linotp 2.0
                if realm == "_default_": # pragma: no cover
                    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("error deleting realm: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, exx)

        finally:
            Session.close()



########################################################

    @log_with(log)
    def setPolicy(self, action, **params):
        """
        method:
            system/setPolicy

        description:
            Stores a policy that define ACL or behaviour of several different
            actions in privacyIDEA. 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:
            param.update(remove_session_from_param(request.params))

            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("saving policy %r" % p_param)
                ret = setPolicy(p_param)
                log.debug("policy %s successfully saved." % name)

                string = "setPolicy " + name
                res[string] = ret

                c.audit['success'] = True

                Session.commit()
            else:
                log.error("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("error saving policy: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, exx)

        finally:
            Session.close()


########################################################
    @log_with(log)
    def policies_flexi(self, action, **params):
        '''
        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)

            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("retrieving policy name: %s, realm: %s, scope: %s, sort:%s by %s"
                % (name, realm, scope, sortorder, sortname))
            pols = self.Policy.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("error in policy flexi: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, exx)

        finally:
            Session.close()


########################################################
    @log_with(log)
    def getPolicyDef(self, action, **params):
        '''
        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("getting policy definitions: %r" % param)

            scope = getParam(param, "scope", optional)
            pol = get_policy_definitions(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("error getting policy definitions: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, exx)

        finally:
            Session.close()


#########################################################
    @log_with(log)
    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 = {}

        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('no policy for tokentype %r found (%r)'
                             % (tok, exx))

        return pol

#########################################################
    @log_with(log)
    def importPolicy(self, action, **params):
        '''
        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:
            policy_file = request.POST['file']
            fileString = ""
            log.debug("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("Field storage file: %s", policy_file)
                fileString = policy_file.value
                sendResultMethod = sendXMLResult
                sendErrorMethod = sendXMLError
            else:
                fileString = policy_file
            log.debug("fileString: %s", fileString)

            if fileString == "":
                log.error("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("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("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("failed! %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendErrorMethod(response, exx)

        finally:
            Session.close()


############################################################
    @log_with(log)
    def checkPolicy(self, action, **params):
        '''
        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", "license"]:
                pol = self.Policy.getPolicy({"scope":scope})
                if len(pol) > 0:
                    # Policy active for this scope!
                    pol = self.Policy.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("checking policy for client %s, scope %s, action %s, realm %s and user %s" %
                          (client, scope, action, realm, user))

                pol = self.Policy.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("error checking policy: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, exx)

        finally:
            Session.close()

##########################################################################
    @log_with(log)
    def getPolicy(self, action, **params):
        """
        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)
        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("retrieving policy name: %s, realm: %s, scope: %s"
                      % (name, realm, scope))
            pol = {}
            if name != None:
                for nam in name.split(','):
                    poli = self.Policy.getPolicy({'name':nam, 'realm':realm, 'scope': scope}, display_inactive=display_inactive)
                    pol.update(poli)
            else:
                pol = self.Policy.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 = self.Policy.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("error getting policy: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, exx)

        finally:
            Session.close()

########################################################
    @log_with(log)
    def delPolicy(self, action, **params):
        """
        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)
            name = getParam(param, "name", required)
            log.debug("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("error deleting policy: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, exx)

        finally:
            Session.close()


########################################################
    @log_with(log)
    def setupSecurityModule(self, action, **params):

        res = {}

        try:
            params = getLowerParams(request.params)
            hsm_id = params.get('hsm_id', None)

            from privacyidea.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("setup failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, exx)

        finally:
            Session.close()
Esempio n. 4
0
class OcraController(BaseController):
    '''
    The OcraController implements challenges/response tokens according to RFC 6287
    '''

    @log_with(log)
    def __before__(self, action, **params):
        '''
        Here we see, what action is to be called and check the authorization
        '''

        try:
            c.audit['success'] = False
            c.audit['client'] = get_client()
            self.Policy = PolicyClass(request, config, c,
                                      get_privacyIDEA_config(),
                                      token_type_list = get_token_type_list())
            if action != "check_t":
                self.before_identity_check(action)

            return response

        except webob.exc.HTTPUnauthorized as acc:
            ## the exception, when an abort() is called if forwarded
            log.error("%r webob.exception %r" % (action, acc))
            log.error(traceback.format_exc())
            Session.rollback()
            Session.close()
            raise acc

        except Exception as exx:
            log.error("%r exception %r" % (action, exx))
            log.error(traceback.format_exc())
            Session.rollback()
            Session.close()
            return sendError(response, exx, context='before')

        finally:
            pass

    @log_with(log)
    def __after__(self, action, **params):
        c.audit['administrator'] = getUserFromRequest(request).get("login")
        self.audit.log(c.audit)

        return response


########################################################
    @log_with(log)
    def request(self, action, **params):
        """
        method:
            orcra/request

        description:
            request a challenge for a user or for a serial number (token).

        arguments:
            * serial: (required - string)
                    Serial number of the token, for which a challenge should
                    be generated (either serial or user is required)

            * user:   (required  - string)
                    The user for whose token a challenge should be generated
                    If the user has more than one token, an error is returend.
                    (either serial or user is required)

            * data:   (required - String: URLendoced)
                    These are the display data, that can be used to generate the challenge

        remark:
            the app will report a wrong qrcode, if the policy
             {'authentication' : qrtanurl=https://localhost }
            is not defined !!

        returns:

            A JSON respone::

                        {
                            "version": "privacyIDEA 2.4",
                            "jsonrpc": "2.0",
                            "result": {
                                "status": true,
                                "value": false,
                            },
                            "detail": {
                                    "transactionid" : TRANSAKTIONSID,
                                    "data" : DATAOBJECT,
                            }
                        }

            * transactionid:
                    This is the transaction ID, that is used later for
                    verifying the Return code /TAN.

            * data:
                    This is an object (URL) which can be used to generate a
                    QR-Coide to be displayed to the QRTAN App


        exception:

        """
        res = {}
        description = 'ocra/request: request a challenge for a given user or token (serial). You must either provide a parameter "user" or a parameter "serial".'
        dataobj = ""

        try:
            param = getLowerParams(request.params)

            self.Policy.checkPolicyPre('ocra', "request")

            serial = getParam(param, 'serial', optional)
            user = getUserFromParam(param, optional)

            if user.isEmpty() and serial is None:
                ## raise exception
                log.error("user or serial is required")
                raise ParameterError("Usage: %s" % description, id=77)

            message = getParam(param, 'data'  , optional)
            if message is None:
                message = ''

            ## ocra token
            tokens = getTokens4UserOrSerial(user, serial)

            if len(tokens) > 1 :
                error = ('More than one token found: unable to create challenge '
                        'for (u:%r,s:%r)!' % (user, serial))
                log.error(error)
                raise Exception(error)

            if len(tokens) == 0:
                error = ('No token found: unable to create challenge for'
                          ' (u:%r,s:%r)!' % (user, serial))
                log.error(error)
                raise Exception(error)

            ocra = tokens[0]
            (transId, challenge, res, url) = ocra.challenge(message)

            u = urlencode({'u':str(url.encode("utf-8"))})

            uInfo = {'tr': transId, 'ch' : challenge,
                      'me': str(message.encode("utf-8")), 'u': u[2:]}
            detail = {"transactionid"   : transId,
                      'challenge'       : challenge,
                      'message'         : str(message.encode("utf-8")),
                      'url'             : str(url.encode("utf-8")),
                     }

            ## create the app_url from the data'''
            dataobj = 'lseqr://req?%s' % (str(urlencode(uInfo)))

            ## append the signature to the url '''
            signature = {'si' : ocra.signData(dataobj)}
            uInfo['si'] = signature
            dataobj = '%s&%s' % (dataobj, str(urlencode(signature)))

            detail["data"] = dataobj

            c.audit['success'] = res
            #c.audit['info'] += "%s=%s, " % (k, value)

            Session.commit()
            qr = getParam(param, 'qr', optional)
            if qr is not None:
                param['alt'] = detail
                return sendQRImageResult(response, dataobj, param)
            else:
                return sendResult(response, res, 1, opt=detail)

        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:
            log.error("failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(exx))

        finally:
            Session.close()



    ## https://privacyideaserver/ocra/check_t?transactionid=TRANSACTIONID&pass=TAN
    @log_with(log)
    def check_t(self, action, **params):
        """
        method:
            orcra/check_t

        description:
            verify the response of the ocra token

        arguments:
            * transactionid:  (required - string)
                    Dies ist eine Transaktions-ID, die bei der Challenge ausgegeben wurde.

            * pass:   (required - string)
                    die response, die der OCRA Token auf Grund der Challenge berechnet hat

        returns:

            A JSON response::

                {
                 "version": "privacyIDEA 2.4",
                 "jsonrpc": "2.0",
                 "result": {
                     "status": true,
                     "value": {
                         "failcount" : 3,
                         "result": false
                        }
                    },
                 "id": 0
                }

        exception:

        """
        res = {}
        description = 'ocra/check_t: validate a token request.'

        try:
            param = getLowerParams(request.params)

            #checkPolicyPre('ocra', "check_t" )

            passw = getParam(param, 'pass'  , optional)
            if passw is None:
                ## raise exception'''
                log.error("missing pass ")
                raise ParameterError("Usage: %s Missing parameter 'pass'." % description, id=77)

            transid = getParam(param, 'transactionid', optional)
            if transid is None:
                ## raise exception'''
                log.error("missing transactionid, user or serial number of token")
                raise ParameterError("Usage: %s Missing parameter 'transactionid'." % description, id=77)

            ## if we have a transaction, get serial from this challenge
            value = {}
            ocraChallenge = OcraTokenClass.getTransaction(transid)
            if ocraChallenge is not None:
                serial = ocraChallenge.tokenserial

                tokens = getTokens4UserOrSerial(serial=serial)
                if len(tokens) == 0 or len(tokens) > 1:
                    raise Exception('tokenmismatch for token serial: %s'
                                    % (unicode(serial)))

                theToken = tokens[0]
                tok = theToken.token
                desc = tok.get()
                realms = desc.get('privacyIDEA.RealmNames')
                if realms is None or len(realms) == 0:
                    realm = getDefaultRealm()
                elif len(realms) > 0:
                    realm = realms[0]

                userInfo = getUserInfo(tok.privacyIDEAUserid, tok.privacyIDEAIdResolver, tok.privacyIDEAIdResClass)
                user = User(login=userInfo.get('username'), realm=realm)

                (ok, opt) = checkSerialPass(serial, passw, user=user,
                                     options={'transactionid':transid})

                failcount = theToken.getFailCount()
                value['result'] = ok
                value['failcount'] = int(failcount)

            else:
                ## no challenge found for this transid
                value['result'] = False
                value['failure'] = 'No challenge for transaction %r found'\
                                    % transid

            c.audit['success'] = res
            #c.audit['info'] += "%s=%s, " % (k, value)

            Session.commit()
            return sendResult(response, value, 1)

        except Exception as e :
            log.error("failed: %r" % e)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendResult(response, unicode(e), 0)

        finally:
            Session.close()


    '''
        https://privacyideaserver/ocra/checkstatus?transactionid=TRANSACTIONID
        https://privacyideaserver/ocra/checkstatus?serial=SERIENNUMMER
        https://privacyideaserver/ocra/checkstatus?user=BENUTZER
    '''
    @log_with(log)
    def checkstatus(self, action, **params):
        """
        method:
            orcra/checkstatus

        description:
            Methode zur assynchronen Ueberpruefungen eines Challenge Response Valiadation requests

        arguments:

            * transactionid:  (required one of  - string - (hex))
                    Dies ist eine Transaktions-ID, die bei der Challenge ausgegeben wurde.

            * serial: (required one of  - string)
                    die Serien Nummer des OCRA Token

            * user: (required one of  - string)
                    die Benutzer eines Tokens

            required is one of (user,serial,transactionid)

        returns:

            A JSON response::

                {
                 "version": "privacyIDEA 2.4",
                 "jsonrpc": "2.0",
                 "result": {
                     "status": true,
                     "value": [
                             {
                             "serial": SERIENNUMMER1,
                             "transactionid": TRANSACTIONID1,
                             "received_tan": true,
                             "valid_tan": true,
                             "failcount": 0
                             },
                             {
                             "serial": SERIENNUMMER1,
                             "transactionid": TRANSACTIONID2,
                             "received_tan": false,
                             "valid_tan": false,
                             "failcount": 0
                             },
                             {
                             "serial": SERIENNUMMER2,
                             "transactionid": TRANSACTIONID3,
                             "received_tan": true,
                             "valid_tan": false,
                             "failcount": 2
                             },
                         ]
                     },
                 "id": 0
                 }

        exception:

        """
        res = {}
        description = 'ocra/checkstatus: check the token status - for assynchronous verification. Missing parameter: You need to provide one of the parameters "transactionid", "user" or "serial"'

        try:
            param = getLowerParams(request.params)

            self.Policy.checkPolicyPre('ocra', "status")

            transid = getParam(param, 'transactionid'   , optional)
            user = getUserFromParam(param, optional)
            #user   = getParam(param, 'user'          ,optional)
            serial = getParam(param, 'serial'          , optional)

            if transid is None and user.isEmpty() and serial is None:
                ## raise exception
                log.error("missing transactionid, user or serial number for token")
                raise ParameterError("Usage: %s" % description, id=77)

            tokens = []
            serials = set()
            status = []

            if serial is not None:
                serials.add(serial)

            ## if we have a transaction, get serial from this challenge
            if transid is not None :
                ocraChallenge = None
                try:
                    ocraChallenge = OcraTokenClass.getTransaction(transid)
                except:
                    pass
                if ocraChallenge is not None:
                    serials.add(ocraChallenge.tokenserial)

            ## if we have a serial number of  token
            if len(serials) > 0:
                for serial in serials:
                    tokens.extend(getTokens4UserOrSerial(serial=serial))

            ## if we have a user
            if user.isEmpty() == False:
                try:
                    tokens.extend(getTokens4UserOrSerial(user=user))
                except:
                    log.warning("no token or user %r found!" % user)

            for token in tokens:
                if token.getType() == 'ocra':
                    challenges = []
                    if transid is None:
                        serial = token.getSerial()
                        challenges = OcraTokenClass.getTransactions4serial(serial)
                    else:
                        challenges.append(OcraTokenClass.getTransaction(transid))

                    for challenge in challenges:
                        stat = token.getStatus(challenge.transid)
                        if stat is not None and len(stat) > 0:
                            status.append(stat)

            res['values'] = status
            c.audit['success'] = res

            Session.commit()
            return sendResult(response, res, 1)

        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:
            log.error("failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendResult(response, unicode(exx), 0)

        finally:
            Session.close()



    @log_with(log)
    def getActivationCode(self, action, **params):
        '''
        method:
            orcra/getActivationCode

        description:
            returns an valid example activcation code

        arguments:
            ./.

        returns:
            JSON with     "activationcode": "JZXW4ZI=2A"
        '''

        from privacyidea.lib.crypto import createActivationCode

        res = {}
        #description = 'ocra/getActivationCode'

        try:
            params = getLowerParams(request.params)

            self.Policy.checkPolicyPre('ocra', "activationcode")

            ac = str(params.get('activationcode'))
            activationCode = createActivationCode(acode=ac)
            res = {'activationcode':activationCode}

            Session.commit()
            return sendResult(response, res, 1)

        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:
            log.error("failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(exx), 0)

        finally:
            Session.close()


    @log_with(log)
    def calculateOtp(self, action, **params):
        '''

        '''
        from privacyidea.lib.crypto import kdf2
        from privacyidea.lib.ocra import OcraSuite
        from datetime import datetime

        from urlparse import urlparse
        from urlparse import parse_qs

        res = {}
        #description = 'ocra/calculateOtp: calculate the first otp from the given init2 response '

        try:
            params = getLowerParams(request.params)

            self.Policy.checkPolicyPre('ocra', "calcOTP")

            sharedsecret = params.get('sharedsecret')
            activationcode = params.get('activationcode')
            nonce = params.get('nonce')
            ocrasuite = params.get('ocrasuite')
            challenge = params.get('challenge')
            counter = params.get('counter')
            ocrapin = params.get('ocrapin')

            nonce3 = params.get('no')
            ocrasuite3 = params.get('os')
            #serial3         = params.get('se')

            challenge = params.get('challenge')
            counter = params.get('counter')
            ocrapin = params.get('ocrapin')
            init1 = params.get('init1')
            init2 = params.get('init2')

            ## parse init1 '''
            if init1 is not None:
                ## now parse the appurl for the ocrasuite '''
                uri = urlparse(init1.replace('lseqr://', 'http://'))
                qs = uri.query
                qdict = parse_qs(qs)

                ocrasuite2 = qdict.get('os', None)
                if ocrasuite2 is not None and len(ocrasuite2) > 0:
                    ocrasuite2 = ocrasuite2[0]

                if ocrasuite is None:
                    ocrasuite = ocrasuite2

                sharedsecret2 = qdict.get('sh', None)
                if sharedsecret2 is not None and len(sharedsecret2) > 0:
                    sharedsecret2 = sharedsecret2[0]

                if sharedsecret is None:
                    sharedsecret = sharedsecret2

            ## parse init1
            if init2 is not None:
                ## now parse the appurl for the ocrasuite
                uri = urlparse(init2.replace('lseqr://', 'http://'))
                qs = uri.query
                qdict = parse_qs(qs)

                challenge2 = qdict.get('ch', None)
                if challenge2 is not None and len(challenge2) > 0:
                    challenge2 = challenge2[0]
                if challenge is None:
                    challenge = challenge2

                nonce2 = qdict.get('no', None)
                if nonce2 is not None and len(nonce2) > 0:
                    nonce2 = nonce2[0]
                if nonce is None:
                    nonce = nonce2

            if ocrapin is None:
                ocrapin = ''
            if counter is None:
                counter = 0

            if nonce3 is not None:
                nonce = unicode(nonce3)

            if ocrasuite3 is not None:
                ocrasuite = unicode(ocrasuite3)

            ##  now we have all in place for the key derivation to create the new key
            ##     sharedsecret, activationcode and nonce
            key_len = 20
            if ocrasuite.find('-SHA256'):
                key_len = 32
            elif ocrasuite.find('-SHA512'):
                key_len = 64

            if sharedsecret is not None:
                sharedsecret = unicode(sharedsecret)
            if nonce is not None:
                nonce = unicode(nonce)
            if activationcode is not None:
                activationcode = unicode(activationcode)

            newkey = kdf2(sharedsecret, nonce, activationcode, len=key_len)
            ## hnewkey = binascii.hexlify(newkey)
            ocra = OcraSuite(ocrasuite)

            param = {}
            param['C'] = int(counter)
            param['Q'] = unicode(challenge)
            param['P'] = unicode(ocrapin)
            param['S'] = ''
            if ocra.T is not None:
                ## Default value for G is 1M, i.e., time-step size is one minute and the
                ##  T represents the number of minutes since epoch time [UT].
                now = datetime.now()
                stime = now.strftime("%s")
                itime = int(stime)
                param['T'] = itime

            data = ocra.combineData(**param)
            otp = ocra.compute(data, newkey)

            res = {'otp':otp}

            Session.commit()
            return sendResult(response, res, 1)

        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, pe)

        except Exception as e:
            log.error("failed: %r" % e)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(e), 0)

        finally:
            Session.close()
Esempio n. 5
0
class GettokenController(BaseController):

    '''
    The privacyidea.controllers are the implementation of the web-API to talk to the privacyIDEA server.
    The ValidateController is used to validate the username with its given OTP value.

    The Tagespasswort Token uses this controller to retrieve the current OTP value of
    the Token and be able to set it in the application
    The functions of the GettokenController are invoked like this

        https://server/gettoken/<functionname>

    The functions are described below in more detail.
    '''
    @log_with(log)
    def __before__(self, action, **params):
        try:
            c.audit['client'] = get_client()
            if request.params.get('serial'):
                tokentype = getTokenType(request.params.get('serial'))
            else:
                tokentype = None
            self.Policy = PolicyClass(request, config, c,
                                      get_privacyIDEA_config(),
                                      tokentype = tokentype,
                                      token_type_list = get_token_type_list())
            self.before_identity_check(action)


        except Exception as exx:
            log.error("%r exception %r" % (action, exx))
            log.error(traceback.format_exc())
            Session.rollback()
            Session.close()
            return sendError(response, exx, context='before')

        finally:
            pass

    @log_with(log)
    def __after__(self, action, **params):
        c.audit['administrator'] = getUserFromRequest(request).get("login")
        if request.params.has_key('serial'):
                c.audit['serial'] = request.params['serial']
                c.audit['token_type'] = getTokenType(request.params['serial'])
        self.audit.log(c.audit)
        

    @log_with(log)
    def getmultiotp(self, action, **params):
        '''
        This function is used to retrieve multiple otp values for a given user or a given serial
        If the user has more than one token, the list of the tokens is returend.

        method:
            gettoken/getmultiotp

        
        :param serial: the serial number of the token
        :param count: number of otp values to return
        :param curTime: used ONLY for internal testing: datetime.datetime object
        :type curTime: datetime object
        :param timestamp: the unix time
        :type timestamp: int
        
        :return: JSON response
        '''

        getotp_active = config.get("privacyideaGetotp.active")
        if "True" != getotp_active:
            return sendError(response, "getotp is not activated.", 0)

        param = request.params
        ret = {}

        try:
            serial = getParam(param, "serial", required)
            tokenrealms = getTokenRealms(serial)
            count = int(getParam(param, "count", required))
            curTime = getParam(param, "curTime", optional)
            timestamp = getParam(param, "timestamp", optional)
            view = getParam(param, "view", optional)

            r1 = self.Policy.checkPolicyPre('admin', 'getotp', param,
                                            tokenrealms = tokenrealms)
            log.debug("admin-getotp returned %s" % r1)

            max_count = self.Policy.checkPolicyPre('gettoken', 'max_count', param,
                                                   tokenrealms = tokenrealms)
            log.debug("checkpolicypre returned %s" % max_count)
            if count > max_count:
                count = max_count

            log.debug("retrieving OTP value for token %s" % serial)
            ret = get_multi_otp(serial, count=int(count), curTime=curTime, timestamp=timestamp)
            ret["serial"] = serial

            c.audit['success'] = True
            Session.commit()

            if view:
                c.ret = ret
                return render('/manage/multiotp_view.mako')
            else:
                return sendResult(response, ret , 0)

        except PolicyException as pe:
            log.error("gettoken/getotp policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe), 1)

        except Exception as e:
            log.error("gettoken/getmultiotp failed: %r" % e)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, "gettoken/getmultiotp failed: %s"
                             % unicode(e), 0)

        finally:
            Session.close()


    @log_with(log)
    def getotp(self, action, **params):
        '''
        This function is used to retrieve the current otp value for a given user or a given serial
        If the user has more than one token, the list of the tokens is returend.

        method:
            gettoken/getotp

        arguments:
            user    - username / loginname
            realm   - additional realm to match the user to a useridresolver
            serial  - the serial number of the token
            curTime - used ONY for internal testing: datetime.datetime object

        returns:
            JSON response
        '''

        getotp_active = config.get("privacyideaGetotp.active")
        if "True" != getotp_active:
            return sendError(response, "getotp is not activated.", 0)

        param = request.params
        ret = {}
        res = -1
        otpval = ""
        passw = ""
        serials = []

        try:

            serial = getParam(param, "serial", optional)
            user = getUserFromParam(param, optional)
            curTime = getParam(param, "curTime", optional)

            c.audit['user'] = user.login
            if "" != user.login:
                c.audit['realm'] = user.realm or getDefaultRealm()

            if serial:
                log.debug("retrieving OTP value for token %s" % serial)
            elif user.login:
                log.debug("retrieving OTP value for token for user %s@%s" % (user.login, user.realm))
                toks = getTokens4UserOrSerial(user, serial)
                tokennum = len(toks)
                if tokennum > 1:
                    log.debug("The user has more than one token. Returning the list of serials")
                    res = -3
                    for token in toks:
                        serials.append(token.getSerial())
                elif 1 == tokennum:
                    serial = toks[0].getSerial()
                    log.debug("retrieving OTP for token %s for user %s@%s" %
                                (serial, user.login, user.realm))
                else:
                    log.debug("no token found for user %s@%s" % (user.login, user.realm))
                    res = -4
            else:
                res = -5

            # if a serial was given or a unique serial could be received from the given user.
            if serial:
                tokenrealms = getTokenRealms(serial)
                max_count = self.Policy.checkPolicyPre('gettoken', 'max_count', param,
                                                       tokenrealms = tokenrealms)
                log.debug("checkpolicypre returned %s" % max_count)
                if max_count <= 0:
                    return sendError(response, "The policy forbids receiving OTP values for the token %s in this realm" % serial , 1)

                (res, pin, otpval, passw) = getOtp(serial, curTime=curTime)

            c.audit['success'] = True

            if int(res) < 0:
                ret['result'] = False
                if -1 == otpval:
                    ret['description'] = "No Token with this serial number"
                if -2 == otpval:
                    ret['description'] = "This Token does not support the getOtp function"
                if -3 == otpval:
                    ret['description'] = "The user has more than one token"
                    ret['serials'] = serials
                if -4 == otpval:
                    ret['description'] = "No Token found for this user"
                if -5 == otpval:
                    ret['description'] = "you need to provide a user or a serial"
            else:
                ret['result'] = True
                ret['otpval'] = otpval
                ret['pin'] = pin
                ret['pass'] = passw

            Session.commit()
            return sendResult(response, ret , 0)

        except PolicyException as pe:
            log.error("gettoken/getotp policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe), 1)

        except Exception as e:
            log.error("gettoken/getotp failed: %r" % e)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, "gettoken/getotp failed: %s" % unicode(e), 0)

        finally:
            Session.close()
Esempio n. 6
0
class MachineController(BaseController):

    @log_with(log)
    def __before__(self, action, **params):
        '''
        '''
        try:
            c.audit['success'] = False
            c.audit['client'] = get_client()
            self.Policy = PolicyClass(request, config, c,
                                      get_privacyIDEA_config(),
                                      tokenrealms=request.params.get('serial'),
                                      token_type_list=get_token_type_list())
            self.set_language()

            self.before_identity_check(action)

            Session.commit()
            return request

        except webob.exc.HTTPUnauthorized as acc:
            # the exception, when an abort() is called if forwarded
            log.info("%r: webob.exception %r" % (action, acc))
            log.info(traceback.format_exc())
            Session.rollback()
            Session.close()
            raise acc

        except Exception as exx:  # pragma: no cover
            log.error("exception %r" % (action, exx))
            log.error(traceback.format_exc())
            Session.rollback()
            Session.close()
            return sendError(response, exx, context='before')

        finally:
            pass

    @log_with(log)
    def __after__(self, action, **params):
        '''
        '''
        params = {}

        try:
            params.update(request.params)
            c.audit['administrator'] = getUserFromRequest(request).get("login")
            if 'serial' in params:
                    c.audit['serial'] = request.params['serial']
                    c.audit['token_type'] = getTokenType(params.get('serial'))

            self.audit.log(c.audit)

            Session.commit()
            return request

        except Exception as e:  # pragma: no cover
            log.error("unable to create a session cookie: %r" % e)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, e, context='after')

        finally:
            Session.close()

    @log_with(log)
    def create(self, action, **params):
        '''
        Create a new client machine entry

        :param name: the unique name of the machine (required).
                     Can be the FQDN.
        :param desc: description of the machine
        :param ip: The IP address of the machine (required)
        :param decommission: A date when the machine will not be valid anymore

        :return: True or False if the creation was successful.
        '''
        try:
            res = False
            param = {}
            # check machine authorization
            self.Policy.checkPolicyPre('machine', 'create')

            param.update(request.params)
            machine_name = getParam(param, "name", required)
            ip = getParam(param, "ip", required)
            desc = getParam(param, "desc", optional)
            decommission = getParam(param, "decommission", optional)
            machine = create_machine(machine_name,
                                     ip=ip,
                                     desc=desc,
                                     decommission=decommission)
            if machine:
                res = True
            Session.commit()
            c.audit["success"] = True
            return sendResult(response, res, 1)

        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:  # pragma: no cover
            log.error("failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(exx), 0)

        finally:
            Session.close()
            
    @log_with(log)
    def delete(self, action, **params):
        '''
        Delete an existing client machine entry
        
        :param name: the unique name of the machine
        
        :return: value is either true (success) or false (fail)
        '''
        try:
            res = {}
            param = {}
            # check machine authorization
            self.Policy.checkPolicyPre('machine', 'delete')
            param.update(request.params)
            machine_name = getParam(param, "name", required)
            res = delete_machine(machine_name)
            Session.commit()
            c.audit["success"] = True
            return sendResult(response, res, 1)

        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:  # pragma: no cover
            log.error("failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(exx), 0)

        finally:
            Session.close()

    @log_with(log)
    def show(self, action, **params):
        '''
        Returns a list of the client machines.
        
        :param name: Optional parameter to only show this single machine
        
        :return: JSON details
        '''
        try:
            res = {}
            param = {}
            # check machine authorization
            self.Policy.checkPolicyPre('machine', 'show')
            param.update(request.params)
            machine_name = getParam(param, "name", optional)
            
            res = show_machine(machine_name)
            Session.commit()
            c.audit["success"] = True
            return sendResult(response, res, 1)

        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:  # pragma: no cover
            log.error("failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(exx), 0)

        finally:
            Session.close()

    @log_with(log)
    def addtoken(self, action, **params):
        '''
        Add a token and a application to a machine
        
        :param name: Name of the machine
        :param serial: serial number of the token
        :param application: name of the application
        :param option_*: parameter is passed as additional option to
                         the machinetoken to be stored in
                         machine_t_options table.
                         In case of LUKS application this can be
                         "option_slot"
        '''
        try:
            res = False
            param = {}
            options = {}
            # check machine authorization
            self.Policy.checkPolicyPre('machine', 'addtoken')
            param.update(request.params)
            machine_name = getParam(param, "name", required)
            serial = getParam(param, "serial", required)
            application = getParam(param, "application", required)
            
            if application.lower() not in config.get("applications").keys():
                log.error("Unknown application %r. Available applications: "
                          "%r" % (application,
                                  config.get("applications").keys()))
                raise Exception("Unkown application!")
            
            for p in param.keys():
                if p.startswith("option_"):
                    options[p] = param.get(p)
            
            mt = addtoken(machine_name,
                          serial,
                          application,
                          options=options)
            if mt:
                res = True
            Session.commit()
            c.audit["success"] = True
            return sendResult(response, res, 1)

        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:  # pragma: no cover
            log.error("failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(exx), 0)

        finally:
            Session.close()

    @log_with(log)
    def addoption(self, action, **params):
        '''
        Add an option to a machinetoken definition
        
        :param mtid: id of the machine token definition
        :param name: machine_name
        :param serial: serial number of the token
        :param application: application
        :param option_*: name of the option.
                         In case of LUKS application this can be
                         "option_slot"
                         
        You either need to provide the machine-token-id (mtid) directly or
        you need to provide the tuple (name, serial, application)
        '''
        try:
            num = -1
            param = {}
            options = {}
            # check machine authorization
            self.Policy.checkPolicyPre('machine', 'addtoken')
            param.update(request.params)
            mtid = getParam(param, "mtid", optional)
            machine_name = getParam(param, "name", optional)
            serial = getParam(param, "serial", optional)
            application = getParam(param, "application", optional)
            if not (mtid or (machine_name and serial and application)):
                raise ParameterError("You need to specify either mtid or"
                                     "the tuple name, serial, application",
                                     id=201)
               
            for p in param.keys():
                if p.startswith("option_"):
                    options[p] = param.get(p)
            
            num = addoption(mtid,
                            name=machine_name,
                            serial=serial,
                            application=application,
                            options=options)
            Session.commit()
            c.audit["success"] = True
            return sendResult(response, num, 1)

        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:  # pragma: no cover
            log.error("failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(exx), 0)

        finally:
            Session.close()

    @log_with(log)
    def deloption(self, action, **params):
        '''
        Delete an option from a machinetoken definition
        
        :param mtid: id of the machine token definition
        :param name: machine_name
        :param serial: serial number of the token
        :param application: application
        :param key: key of the option to delete
                         
        You either need to provide the machine-token-id (mtid) directly or
        you need to provide the tuple (name, serial, application)
        '''
        try:
            num = -1
            param = {}
            options = {}
            # check machine authorization
            self.Policy.checkPolicyPre('machine', 'deltoken')
            param.update(request.params)
            mtid = getParam(param, "mtid", optional)
            machine_name = getParam(param, "name", optional)
            serial = getParam(param, "serial", optional)
            option_key = getParam(param, "key", required)
            application = getParam(param, "application", optional)
            if not (mtid or (machine_name and serial and application)):
                raise ParameterError("You need to specify either mtid or"
                                     "the tuple name, serial, application",
                                     id=201)
            num = deloption(mtid,
                            name=machine_name,
                            serial=serial,
                            application=application,
                            key=option_key)
            Session.commit()
            c.audit["success"] = True
            return sendResult(response, num, 1)

        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:  # pragma: no cover
            log.error("failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(exx), 0)

        finally:
            Session.close()

    @log_with(log)
    def deltoken(self, action, **params):
        '''
        delete a token and a application from a machine
        
        :param name: Name of the machine
        :param serial: serial number of the token
        :param application: name of the application
        '''
        try:
            res = False
            param = {}
            # check machine authorization
            self.Policy.checkPolicyPre('machine', 'deltoken')
            param.update(request.params)
            machine_name = getParam(param, "name", required)
            serial = getParam(param, "serial", required)
            application = getParam(param, "application", required)
            
            res = deltoken(machine_name, serial, application)
            Session.commit()
            c.audit["success"] = True
            return sendResult(response, res, 1)

        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:  # pragma: no cover
            log.error("failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(exx), 0)
        finally:
            Session.close()

    @log_with(log)
    def showtoken(self, action, **params):
        '''
        show a token and a application from a machine
        This function is used in the flexigrid management
        
        :param name: Name of the machine
        :param serial: serial number of the token
        :param application: name of the application
        :param flexi: if set to 1, we do return flexigrid input
        '''
        try:
            res = False
            param = {}
            # check machine authorization
            self.Policy.checkPolicyPre('machine', 'showtoken')
            param.update(request.params)
            machine_name = getParam(param, "name", optional)
            serial = getParam(param, "serial", optional)
            application = getParam(param, "application", optional)
            # if set, this should be returned for flexigrid
            flexi = getParam(param, "flexi", optional)

            res = showtoken(machine_name,
                            serial,
                            application,
                            flexi=flexi,
                            params=param)
            Session.commit()
            c.audit["success"] = True
            if flexi:
                response.content_type = 'application/json'
                return json.dumps(res, indent=3)
            else:
                return sendResult(response, res, 1)

        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:  # pragma: no cover
            log.error("failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(exx), 0)

        finally:
            Session.close()

    @log_with(log)
    def gettokenapps(self, action, **params):
        '''
        returns the apps and the authentication information
        for the given machine.

        If an application is given only the authentication item for
        this application is returned. otherwise the application items
        for all applications are returned.

        TODO: Authenticate the client machine

        :param name: the machine name -
                    otherwise the machine is identified by the IP
        :type name: string, optional
        :param application: the name of the application. If the application is
                            given the response will also conatin the auth_item
        :type application: string, optional
        :param serial: The serial number of the token
        
        :return: dictionary with machine and authentication information
        
        
        {"total": 2,
         "machines":  { 1 : {"application": "luks",
                             "auth_item": {"challenge": "hex...",
                                           "response":: "hex..."},
                             "id": 1,
                             "ip": 10.0.0.1,
                             "machine_id": 1,
                             "machinename": "computerABC",
                             "serial": "<serialnumber of token>",
                             "token_id": 1
                            },
                        2 : ...
                      }
        }
        '''
        try:
            res = False
            param = {}
            self.Policy.checkPolicyPre('machine', 'gettokenapps')
            param.update(request.params)
            machine_name = getParam(param, "name", optional)
            application = getParam(param, "application", optional)
            serial = getParam(param, "serial", optional)
            # In case of LUKS and Yubikey we need the client to
            # pass the challenge as the challenge is the Password
            challenge = getParam(param, "challenge", optional)
            client_ip = get_client()
            
            if application:
                if application not in config.get("applications").keys():
                    log.error("Unknown application %r. Available applications:"
                              "%r" % (application,
                                      config.get("applications").keys()))
            application_module = config.get("applications").get(application)
            
            res = get_token_apps(machine=machine_name,
                                 application=application,
                                 application_module=application_module,
                                 serial=serial,
                                 client_ip=client_ip,
                                 challenge=challenge)
            Session.commit()
            c.audit["success"] = True
            return sendResult(response, res, 1)

        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:  # pragma: no cover
            log.error("failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(exx), 0)

        finally:
            Session.close()
            
    @log_with(log)
    def getapplications(self, action, **params):
        '''
        Returns a list of available applications
        '''
        try:
            return sendResult(response, config.get("applications").keys())
        
        except PolicyException as pe:
            log.error("policy failed: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe))

        except Exception as exx:  # pragma: no cover
            log.error("failed: %r" % exx)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(exx), 0)

        finally:
            Session.close()
            
Esempio n. 7
0
class ManageController(BaseController):

    @log_with(log)
    def __before__(self, action, **params):

        try:           
            c.audit['success'] = False
            c.audit['client'] = get_client()
            self.set_language()

            c.version = get_version()
            c.licenseinfo = get_copyright_info()
            self.Policy = PolicyClass(request, config, c,
                                      get_privacyIDEA_config(),
                                      token_type_list = get_token_type_list())
            c.polDefs = get_policy_definitions()

            self.before_identity_check(action)

            c.tokenArray = []
            c.user = self.authUser.login
            c.realm = self.authUser.realm

        except webob.exc.HTTPUnauthorized as acc:
            ## the exception, when an abort() is called if forwarded
            log.info("%r webob.exception %r" % (action, acc))
            log.info(traceback.format_exc())
            Session.rollback()
            Session.close()
            raise acc

        except Exception as exx:
            log.error("exception %r" % (action, exx))
            log.error(traceback.format_exc())
            Session.rollback()
            Session.close()
            return sendError(response, exx, context='before')

        finally:
            pass


    @log_with(log)
    def __after__(self, action, **params):

        if c.audit['action'] in [ 'manage/tokenview_flexi',
                                'manage/userview_flexi' ]:
            c.audit['administrator'] = getUserFromRequest(request).get("login")
            if request.params.has_key('serial'):
                    c.audit['serial'] = request.params['serial']
                    c.audit['token_type'] = getTokenType(request.params['serial'])

            self.audit.log(c.audit)


    @log_with(log)
    def index(self, action, **params):
        '''
        This is the main function of the management web UI
        '''

        try:
            c.title = "privacyIDEA Management"
            admin_user = getUserFromRequest(request)
            if admin_user.has_key('login'):
                c.admin = admin_user['login']

            log.debug("importers: %s" % IMPORT_TEXT)
            c.importers = IMPORT_TEXT

            ## add render info for token type config
            confs = _getTokenTypeConfig('config')
            token_config_tab = {}
            token_config_div = {}
            for conf in confs:
                tab = ''
                div = ''
                try:
                    #loc = conf +'_token_settings'
                    tab = confs.get(conf).get('title')
                    #tab = '<li ><a href=#'+loc+'>'+tab+'</a></li>'

                    div = Template(confs.get(conf).get('html')).render()
                    #div = +div+'</div>'
                except Exception as e:
                    log.debug('no config info for token type %s  (%r)' % (conf, e))

                if tab is not None and div is not None and len(tab) > 0 and len(div) > 0:
                    token_config_tab[conf] = tab
                    token_config_div[conf] = div

            c.token_config_tab = token_config_tab
            c.token_config_div = token_config_div

            ##  add the enrollment fragments from the token definition
            ##  tab: <option value="ocra">${_("OCRA - challenge/response Token")}</option>
            ##  div: "<div id='"+ tt + "'>"+enroll+"</div>"
            enrolls = _getTokenTypeConfig('init')

            token_enroll_tab = {}
            token_enroll_div = {}
            for conf in enrolls:
                tab = ''
                div = ''
                try:
                    tab = enrolls.get(conf).get('title')
                    div = enrolls.get(conf).get('html')
                except Exception as e:
                    log.debug('no enrollment info for token type %s  (%r)' % (conf, e))

                if tab is not None and div is not None and len(tab) > 0 and len(div) > 0:
                    token_enroll_tab[conf] = tab
                    token_enroll_div[conf] = div

            c.token_enroll_tab = token_enroll_tab
            c.token_enroll_div = token_enroll_div

            c.tokentypes = _getTokenTypes()

            http_host = request.environ.get("HTTP_HOST")
            url_scheme = request.environ.get("wsgi.url_scheme")
            c.logout_url = "%s://%s/account/logout" % (url_scheme, http_host)

            Session.commit()
            ren = render('/manage/start.mako')
            return ren

        except PolicyException as pe:
            log.error("Error during checking policies: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe), 1)

        except Exception as ex:
            log.error("failed! %r" % ex)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, ex)

        finally:
            Session.close()

            
##### TODO: CKO: remove it. It is not used
#
#    def tokentype(self):
#        '''
#        '''
#        c.title = 'TokenTypeInfo'
#        g = config['pylons.app_globals']
#        tokens = g.tokenclasses
#        ttinfo = []
#        ttinfo.extend(tokens.keys())
#        for tok in tokens:
#            tclass = tokens.get(tok)
#            tclass_object = newToken(tclass)
#            if hasattr(tclass_object, 'getClassType'):
#                ii = tclass_object.getClassType()
#                ttinfo.append(ii)
#
#        c.tokeninfo = ttinfo
#
#        return render('/manage/tokentypeinfo.mako')

    def policies(self):
        '''
        This is the template for the policies TAB
        '''
        c.title = "privacyIDEA Management - Policies"
        return render('/manage/policies.mako')

    def machines(self):
        '''
        This is the template for the policies TAB
        '''
        c.title = "privacyIDEA Management - Machines"
        return render('/manage/machines.mako')

    def audittrail(self):
        '''
        This is the template for the audit trail TAB
        '''
        c.title = "privacyIDEA Management - Audit Trail"
        return render('/manage/audit.mako')


    def tokenview(self):
        '''
        This is the template for the token TAB
        '''
        c.title = "privacyIDEA Management"
        c.tokenArray = []
        return render('/manage/tokenview.mako')


    def userview(self):
        '''
        This is the template for the token TAB
        '''
        c.title = "privacyIDEA Management"
        c.tokenArray = []
        return render('/manage/userview.mako')

    def custom_style(self):
        '''
        If this action was called, the user hasn't created a custom-style.css yet. To avoid hitting
        the debug console over and over, we serve an empty file.
        '''
        response.headers['Content-type'] = 'text/css'
        return ''

    @log_with(log)
    def tokenview_flexi(self, action, **params):
        '''
        This function is used to fill the flexigrid.
        Unlike the complex /admin/show function, it only returns a
        simple array of the tokens.
        '''
        param = request.params

        try:
            #serial  = getParam(param,"serial",optional)
            c.page = getParam(param, "page", optional)
            c.filter = getParam(param, "query", optional)
            c.qtype = getParam(param, "qtype", optional)
            c.sort = getParam(param, "sortname", optional)
            c.dir = getParam(param, "sortorder", optional)
            c.psize = getParam(param, "rp", optional)

            filter_all = None
            filter_realm = None
            user = User()

            if c.qtype == "loginname":
                if "@" in c.filter:
                    (login, realm) = c.filter.split("@")
                    user = User(login, realm)
                else:
                    user = User(c.filter)

            elif c.qtype == "all":
                filter_all = c.filter
            elif c.qtype == "realm":
                filter_realm = c.filter

            # check admin authorization
            res = self.Policy.checkPolicyPre('admin', 'show', param , user=user)

            filterRealm = res['realms']
            # check if policies are active at all
            # If they are not active, we are allowed to SHOW any tokens.
            pol = self.Policy.getAdminPolicies("show")
            # If there are no admin policies, we are allowed to see all realms
            if not pol['active']:
                filterRealm = ["*"]

            # check if we only want to see ONE realm or see all realms we are allowerd to see.
            if filter_realm:
                if filter_realm in filterRealm or '*' in filterRealm:
                    filterRealm = [filter_realm]

            log.debug("admin >%s< may display the following realms: %s" % (pol['admin'], pol['realms']))
            log.debug("page: %s, filter: %s, sort: %s, dir: %s" % (c.page, c.filter, c.sort, c.dir))

            if c.page is None:
                c.page = 1
            if c.psize is None:
                c.psize = 20

            log.debug("calling TokenIterator for user=%s@%s, filter=%s, filterRealm=%s"
                        % (user.login, user.realm, filter_all, filterRealm))
            c.tokenArray = TokenIterator(user, None, c.page , c.psize, filter_all, c.sort, c.dir, filterRealm=filterRealm)
            c.resultset = c.tokenArray.getResultSetInfo()
            # If we have chosen a page to big!
            lines = []
            for tok in c.tokenArray:
                lines.append(
                    { 'id' : tok['privacyIDEA.TokenSerialnumber'],
                        'cell': [
                            tok['privacyIDEA.TokenSerialnumber'],
                            tok['privacyIDEA.Isactive'],
                            tok['User.username'],
                            tok['privacyIDEA.RealmNames'],
                            tok['privacyIDEA.TokenType'],
                            tok['privacyIDEA.FailCount'],
                            tok['privacyIDEA.TokenDesc'],
                            tok['privacyIDEA.MaxFail'],
                            tok['privacyIDEA.OtpLen'],
                            tok['privacyIDEA.CountWindow'],
                            tok['privacyIDEA.SyncWindow'],
                            tok['privacyIDEA.Userid'],
                            tok['privacyIDEA.IdResolver'], ]
                    }
                    )

            # We need to return 'page', 'total', 'rows'
            response.content_type = 'application/json'
            res = { "page": int(c.page),
                "total": c.resultset['tokens'],
                "rows": lines }

            c.audit['success'] = True

            Session.commit()
            return json.dumps(res, indent=3)

        except PolicyException as pe:
            log.error("Error during checking policies: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe), 1)

        except Exception as e:
            log.error("failed: %r" % e)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, e)

        finally:
            Session.close()


    @log_with(log)
    def userview_flexi(self, action, **params):
        '''
        This function is used to fill the flexigrid.
        Unlike the complex /admin/userlist function, it only returns a
        simple array of the tokens.
        '''
        param = request.params

        try:
            #serial  = getParam(param,"serial",optional)
            c.page = getParam(param, "page", optional)
            c.filter = getParam(param, "query", optional)
            qtype = getParam(param, "qtype", optional)
            c.sort = getParam(param, "sortname", optional)
            c.dir = getParam(param, "sortorder", optional)
            c.psize = getParam(param, "rp", optional)
            c.realm = getParam(param, "realm", optional)

            user = getUserFromParam(param, optional)
            # check admin authorization
            # check if we got a realm or resolver, that is ok!
            self.Policy.checkPolicyPre('admin', 'userlist', { 'user': "******", 'realm' : c.realm })

            if c.filter == "":
                c.filter = "*"

            log.debug("page: %s, filter: %s, sort: %s, dir: %s"
                      % (c.page, c.filter, c.sort, c.dir))

            if c.page is None:
                c.page = 1
            if c.psize is None:
                c.psize = 20

            c.userArray = getUserList({ qtype:c.filter,
                                       'realm':c.realm }, user)
            c.userNum = len(c.userArray)

            lines = []
            for u in c.userArray:
                # shorten the useridresolver, to get a better display value
                resolver_display = ""
                if "useridresolver" in u:
                    if len(u['useridresolver'].split(".")) > 3:
                        resolver_display = u['useridresolver'].split(".")[-1] + " (" + u['useridresolver'].split(".")[-3] + ")"
                    else:
                        resolver_display = u['useridresolver']
                lines.append(
                    { 'id' : u['username'],
                        'cell': [
                            (u['username']) if u.has_key('username') else (""),
                            (resolver_display),
                            (u['surname']) if u.has_key('surname') else (""),
                            (u['givenname']) if u.has_key('givenname') else (""),
                            (u['email']) if u.has_key('email') else (""),
                            (u['mobile']) if u.has_key('mobile') else (""),
                            (u['phone']) if u.has_key('phone') else (""),
                            (u['userid']) if u.has_key('userid') else (""),
                             ]
                    }
                    )

            # sorting
            reverse = False
            sortnames = { 'username' : 0, 'useridresolver' : 1,
                    'surname' : 2, 'givenname' : 3, 'email' : 4,
                    'mobile' :5, 'phone' : 6, 'userid' : 7 }
            if c.dir == "desc":
                reverse = True
            lines = sorted(lines, key=lambda user: user['cell'][sortnames[c.sort]] , reverse=reverse)
            # end: sorting

            # reducing the page
            if c.page and c.psize:
                page = int(c.page)
                psize = int(c.psize)
                start = psize * (page - 1)
                end = start + psize
                lines = lines[start:end]

            # We need to return 'page', 'total', 'rows'
            response.content_type = 'application/json'
            res = { "page": int(c.page),
                "total": c.userNum,
                "rows": lines }

            c.audit['success'] = True

            Session.commit()
            return json.dumps(res, indent=3)

        except PolicyException as pe:
            log.error("Error during checking policies: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe), 1)

        except Exception as e:
            log.error("failed: %r" % e)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, e)

        finally:
            Session.close()


    @log_with(log)
    def tokeninfo(self, action, **params):
        '''
        this returns the contents of /admin/show?serial=xyz in a html format
        '''
        param = request.params

        try:
            serial = getParam(param, 'serial', required)

            filterRealm = ""
            # check admin authorization
            res = self.Policy.checkPolicyPre('admin', 'show', param)

            filterRealm = res['realms']
            # check if policies are active at all
            # If they are not active, we are allowed to SHOW any tokens.
            pol = self.Policy.getAdminPolicies("show")
            if not pol['active']:
                filterRealm = ["*"]

            log.info("admin >%s< may display the following realms: %s" % (res['admin'], filterRealm))
            log.info("displaying tokens: serial: %s", serial)

            toks = TokenIterator(User("", "", ""), serial, filterRealm=filterRealm)

            ### now row by row
            lines = []
            for tok in toks:
                lines.append(tok)
            if len(lines) > 0:

                c.tokeninfo = lines[0]
            else:
                c.tokeninfo = {}

            for k in c.tokeninfo:
                if "privacyIDEA.TokenInfo" == k:
                    try:
                        # Try to convert string to Dictionary
                        c.tokeninfo['privacyIDEA.TokenInfo'] = json.loads(c.tokeninfo['privacyIDEA.TokenInfo'])
                    except:
                        pass

            return render('/manage/tokeninfo.mako')

        except PolicyException as pe:
            log.error("Error during checking policies: %r" % pe)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, unicode(pe), 1)

        except Exception as e:
            log.error("failed! %r" % e)
            log.error(traceback.format_exc())
            Session.rollback()
            return sendError(response, e)

        finally:
            Session.close()