def ValidateRowDict(self,
                        table_name,
                        row_dict,
                        none_ok=False,
                        all_none_ok=False):
        """Checks row dictionaries for correctness in reference to know data types
      and column names in the coresponding table.
  
    Input:
      table_name: string of table name
      row_dict: dict of row
      none_ok: bool of allowance of None as a value in the dict
      all_none_ok: bool of allowance of None as every value in the dict

    Raises:
      UnexpectedDataError: Missing key in dictionary
      UnexpectedDataError: Dictionary has extra key that is not used.
      FunctionError: No Function to check data type
      UnexpectedDataError: Invalid data type
      UnexpectedDataError: Need to fill out at least one value in dict
    """
        main_dict = helpers_lib.GetRowDict(table_name)
        for key in main_dict.iterkeys():
            if (key not in row_dict):
                raise errors.UnexpectedDataError(
                    'Missing key %s in dictionary' % key)

        for key, value in row_dict.iteritems():
            if (key not in main_dict):
                raise errors.UnexpectedDataError(
                    'Dictionary has extra key that is not '
                    'used: %s' % key)

            if (not 'is%s' % main_dict[key] in dir(self)):
                raise errors.FunctionError('No function to check data '
                                           'type: %s' % main_dict[key])
            if (not getattr(self, 'is%s' % main_dict[key])(value)):
                if ((not none_ok and not key.endswith('_id'))
                        or (none_ok and value is not None)):
                    raise errors.UnexpectedDataError(
                        'Invalid data type %s for %s: %s' %
                        (main_dict[key], key, value))

        if (none_ok and not all_none_ok):
            for value in row_dict.values():
                if (value is not None):
                    return
            raise errors.UnexpectedDataError(
                'Need to fill out at least one value '
                'in dict')
Esempio n. 2
0
    def ValidateRecordArgsDict(self,
                               record_type,
                               record_args_dict,
                               none_ok=False):
        """Type checks record args dynamically.

    Inputs:
      record_type: string of record_type
      record_args_dict: dictionary for args keyed by arg name.
                        a filled out dict from GetEmptyRecordArgsDict()
      none_ok: boolean of if None types should be acepted.

    Raises:
      InvalidInputError: dict for record type should have these keys
      FucntionError: No function to check data type
      UnexpectedDataError: Invalid data type
    """
        record_type_dict = self.GetRecordArgsDict(record_type)
        if (not set(record_type_dict.keys()) == set(record_args_dict.keys())):
            raise errors.InvalidInputError(
                'dict for record type %s should have '
                'these keys: %s' % (record_type, record_type_dict))
        if (self.data_validation_instance is None):
            self.InitDataValidation()

        data_validation_methods = dir(data_validation.DataValidation([], []))
        for record_arg_name in record_args_dict.keys():
            if (not 'is%s' % record_type_dict[record_arg_name]
                    in data_validation_methods):
                raise errors.FucntionError(
                    'No function to check data type %s' %
                    record_type_dict[record_arg_name])
            if (none_ok and record_args_dict[record_arg_name] is None):
                continue

            if (not getattr(self.data_validation_instance,
                            'is%s' % record_type_dict[record_arg_name])(
                                record_args_dict[record_arg_name])):
                raise errors.UnexpectedDataError(
                    'Invalid data type %s: %s' %
                    (record_type_dict[record_arg_name],
                     record_args_dict[record_arg_name]))
def CreateRecordsFromZoneObject(zone_object,
                                zone_name=None,
                                view_name=None,
                                zone_origin=None,
                                views_list=None):
    """Creates a list of record dictionaries from a dns.zone object

  Inputs:
    zone_object: a dns.zone object
    zone_origin: a string of the zone origin
    zone_name: string of zone name
    view_name: string of view name
    views_list: list of view dictionaries. 
      Note: This is only necessary if being called by AddFormattedRecords.

  Output:
    make_record_args_list: list of dictionaries of records"""
    if (zone_origin is None):
        zone_origin = str(zone_object.origin)

    make_record_args_list = []
    for record_tuple in zone_object.items():
        record_target = unicode(record_tuple[0])

        for record_set in record_tuple[1].rdatasets:
            ttl = record_set.ttl
            for record_object in record_set.items:
                if (record_object.rdtype == dns.rdatatype.PTR):
                    record_type = u'ptr'
                    assignment_host = FixHostname(unicode(record_object),
                                                  zone_origin)
                    record_args_dict = {u'assignment_host': assignment_host}

                elif (record_object.rdtype == dns.rdatatype.A):
                    record_type = u'a'
                    record_args_dict = {
                        u'assignment_ip': unicode(record_object)
                    }

                elif (record_object.rdtype == dns.rdatatype.AAAA):
                    record_type = u'aaaa'
                    record_args_dict = {
                        u'assignment_ip':
                        unicode(IPy.IP(str(record_object)).strFullsize())
                    }

                elif (record_object.rdtype == dns.rdatatype.CNAME):
                    record_type = u'cname'
                    assignment_host = FixHostname(unicode(record_object),
                                                  zone_origin)
                    record_args_dict = {u'assignment_host': assignment_host}

                elif (record_object.rdtype == dns.rdatatype.HINFO):
                    record_type = u'hinfo'
                    record_args_dict = {
                        u'hardware': unicode(record_object.cpu),
                        u'os': unicode(record_object.os)
                    }

                elif (record_object.rdtype == dns.rdatatype.TXT):
                    record_type = u'txt'
                    record_args_dict = {u'quoted_text': unicode(record_object)}

                elif (record_object.rdtype == dns.rdatatype.MX):
                    record_type = u'mx'
                    mail_server = FixHostname(unicode(record_object.exchange),
                                              zone_origin)
                    record_args_dict = {
                        u'priority': record_object.preference,
                        u'mail_server': mail_server
                    }

                elif (record_object.rdtype == dns.rdatatype.NS):
                    record_type = u'ns'
                    name_server = FixHostname(unicode(record_object),
                                              zone_origin)
                    record_args_dict = {u'name_server': name_server}

                elif (record_object.rdtype == dns.rdatatype.SRV):
                    record_type = u'srv'
                    assignment_host = FixHostname(
                        unicode(record_object.target), zone_origin)
                    record_args_dict = {
                        u'priority': record_object.priority,
                        u'weight': record_object.weight,
                        u'port': record_object.port,
                        u'assignment_host': assignment_host
                    }

                elif (record_object.rdtype == dns.rdatatype.SOA):
                    record_type = u'soa'
                    name_server = FixHostname(unicode(record_object.mname),
                                              zone_origin)
                    admin_email = FixHostname(unicode(record_object.rname),
                                              zone_origin)
                    record_args_dict = {
                        u'name_server': name_server,
                        u'admin_email': admin_email,
                        u'serial_number': record_object.serial,
                        u'retry_seconds': record_object.retry,
                        u'refresh_seconds': record_object.refresh,
                        u'expiry_seconds': record_object.expire,
                        u'minimum_seconds': record_object.minimum
                    }

                else:
                    raise errors.UnexpectedDataError(
                        'Unkown record type: %s.\n %s' %
                        (dns.rdatatype.to_text(
                            record_object.rdtype), record_object))

                if (record_object.rdtype == dns.rdatatype.SOA
                        and view_name == u'any' and views_list):
                    for single_view in views_list:
                        if (single_view != u'any'):
                            make_record_args_list.append({
                                u'record_type':
                                record_type,
                                u'record_target':
                                record_target,
                                u'record_zone_name':
                                zone_name,
                                u'record_arguments':
                                record_args_dict,
                                u'record_view_dependency':
                                single_view,
                                u'ttl':
                                ttl
                            })
                else:
                    make_record_args_list.append({
                        u'record_type': record_type,
                        u'record_target': record_target,
                        u'record_zone_name': zone_name,
                        u'record_arguments': record_args_dict,
                        u'record_view_dependency': view_name,
                        u'ttl': ttl
                    })

    return make_record_args_list
Esempio n. 4
0
    def ListRow(self, *args, **kwargs):
        """Lists rows in the database using a dictionary of tables. Then returns 
    the rows found. Joins are auto generated on the fly based on foreign keys
    in the database.

    Inputs:
      args: pairs of string of table name and dict of rows
      kwargs: lock_rows: default False
              column: column to search range on, if using multiple
                           tables, the column must be in the first table
                           in args.
              range_values: range tuple of values to search within for on column
              is_date: boolean of if range is of dates

      example usage: ListRow('users', user_row_dict,
                             'user_group_assignments', user_assign_row_dict,
                             lock_rows=True)

    Raises:
      TransactionError: Must run StartTansaction before inserting
      UnexpectedDataError: If is_date is specified you must specify column and range
      UnexpectedDataError: If column or range is specified both are needed
      InvalidInputError: Found unknown option(s)
      UnexpectedDataError: No args given, must at least have a pair of table name and row dict
      UnexpectedDataError: Number of unnamed args is not even.
          Args should be entered in pairs of table name and row dict.
      InvalidInputError: Table name not valid
      InvalidInputError: Column not found in row
      UnexpectedDataError: Column in table is not a DateTime type
      UnexpectedDataError: Date from range is not a valid datetime object
      InvalidInputError: Range must be int if is_date is not set
      InvalidInputError: Multiple tables were passed in but no joins were found

    Outputs:
      tuple of row dicts consisting of all the tables that were in the input.
      all column names in the db are unique so no colisions occour
        example: ({'user_name': 'sharrell', 'access_level': 10, 
                   'user_group_assignments_group_name: 'cs',
                   'user_group_assignments_user_name: 'sharrell'},
                  {'user_name': 'sharrell', 'access_level': 10, 
                   'user_group_assignments_group_name: 'eas',
                   'user_group_assignments_user_name: 'sharrell'})
    """
        if (not self.transaction_init):
            raise errors.TransactionError(
                'Must run StartTansaction before getting '
                'data.')
        if (self.data_validation_instance is None):
            self.InitDataValidation()

        valid_tables = helpers_lib.GetValidTables()
        tables = {}
        table_names = []
        lock_rows = False
        column = None
        range_values = ()
        is_date = None
        if (kwargs):
            if ('lock_rows' in kwargs):
                lock_rows = kwargs['lock_rows']
                del kwargs['lock_rows']
            if ('column' in kwargs):
                column = kwargs['column']
                del kwargs['column']
            if ('range_values' in kwargs):
                range_values = kwargs['range_values']
                del kwargs['range_values']
            if ('is_date' in kwargs):
                is_date = kwargs['is_date']
                del kwargs['is_date']
            if (column is None and is_date is not None):
                raise errors.UnexpectedDataError(
                    'If is_date is specified you must '
                    'specify column and range')
            if (bool(column) ^ bool(range_values)):
                raise errors.UnexpectedDataError(
                    'If column or range is specified '
                    'both are needed')
            if (kwargs):
                raise errors.InvalidInputError('Found unknown option(s): '
                                               '%s' % kwargs.keys())

        if (not args):
            raise errors.UnexpectedDataError(
                'No args given, must at least have a '
                'pair of table name and row dict')
        if (len(args) % 2):
            raise errors.UnexpectedDataError(
                'Number of unnamed args is not even. Args '
                'should be entered in pairs of table name '
                'and row dict.')
        count = 0
        for arg in args:
            count += 1
            if (count % 2):
                if (not arg in valid_tables):
                    raise errors.InvalidInputError('Table name not valid: %s' %
                                                   arg)
                current_table_name = arg
            else:
                # do checking in validate row dict to check if it is a dict
                self.data_validation_instance.ValidateRowDict(
                    current_table_name, arg, none_ok=True, all_none_ok=True)
                tables[current_table_name] = arg
                table_names.append(current_table_name)

        if (range_values):
            if (column not in args[1]):
                raise errors.InvalidInputError('Column %s not found in row'
                                               'dictionary: %s' %
                                               (column, args[1]))

            if (is_date):
                if (constants.TABLES[args[0]][column] != 'DateTime'):
                    raise errors.UnexpectedDataError(
                        'column: %s in table %s is not a'
                        'DateTime type' % (column, args[0]))
                for date in range_values:
                    if (not self.data_validation_instance.isDateTime(date)):
                        raise errors.UnexpectedDataError(
                            'Date: %s from range is not a valid '
                            'datetime object' % date)
            else:
                for value in range_values:
                    if (not self.data_validation_instance.isUnsignedInt(value)
                        ):
                        raise errors.InvalidInputError(
                            'Range must be int if is_date '
                            'is not set')
        query_where = []
        if (len(tables) > 1):
            if (not self.foreign_keys):
                self.cursor_execute(
                    'SELECT table_name, column_name, '
                    'referenced_table_name, referenced_column_name '
                    'FROM information_schema.key_column_usage WHERE '
                    'referenced_table_name IS NOT NULL AND '
                    'referenced_table_schema="%s"' % self.db_name)
                self.foreign_keys = self.cursor.fetchall()

            for key in self.foreign_keys:
                if (key['table_name'] in table_names
                        and key['referenced_table_name'] in table_names):

                    query_where.append('(%(table_name)s.%(column_name)s='
                                       '%(referenced_table_name)s.'
                                       '%(referenced_column_name)s)' % key)
            if (not query_where):
                raise errors.InvalidInputError(
                    'Multiple tables were passed in but no '
                    'joins were found')
        column_names = []
        search_dict = {}
        for table_name, row_dict in tables.iteritems():
            for key, value in row_dict.iteritems():
                column_names.append('%s.%s' % (table_name, key))
                if (value is not None):
                    search_dict[key] = value
                    query_where.append('%s%s%s%s' % (key, '=%(', key, ')s'))

        if (range_values):
            search_dict['start'] = range_values[0]
            search_dict['end'] = range_values[1]
            query_where.append(
                '%s%s%s%s' % (column, '>=%(start)s AND ', column, '<=%(end)s'))

        query_end = ''
        if (query_where):
            query_end = 'WHERE %s' % ' AND '.join(query_where)
        if (lock_rows):
            query_end = '%s FOR UPDATE' % query_end

        query = 'SELECT %s FROM %s %s' % (','.join(column_names),
                                          ','.join(table_names), query_end)

        self.cursor_execute(query, search_dict)
        return self.cursor.fetchall()
Esempio n. 5
0
  def Authorize(self, method, record_data=None, current_transaction=False):
    """Check to see if the user is authorized to run the given operation.

    Inputs:
      method:	what the user's trying to do
      record_data: dictionary of target, zone_name, view_name, record_type, 
                   and record_args_dict for the record that is being modified.
                   {'target': 'test_target',
                    'zone_name': 'test_zone',
                    'view_name': 'test_view',
                    'record_type': 'a',
                    'record_args_dict' : {
                        u'assignment_ip' : '192.168.1.1'
                     }
                   }
      current_transaction: bool of if this function is run from inside a
                           transaction in the db_access class

    Raises:
      MaintenanceError: Roster is currently under maintenance.
      MissingDataTypeError: Incomplete record data provided for access method.
      AuthorizationError: Authorization failure.
    """
    function_name, current_args = helpers_lib.GetFunctionNameAndArgs()

    if( not current_transaction ):
      self.db_instance.StartTransaction()
    try:
      maintenance_mode = self.db_instance.CheckMaintenanceFlag()
      if( record_data and record_data.has_key('zone_name') ):
        if( record_data['zone_name'] ):
          pulled_origin = self.db_instance.GetZoneOrigins(
              record_data['zone_name'], record_data['view_name'])

          #Making sure we pulled something that exists
          if( pulled_origin is not None ):
            self.zone_origin_cache[record_data['zone_name']] = pulled_origin[
                record_data['zone_name']]
          else:
            view_name = record_data['view_name']
            if( view_name.endswith('_dep') ):
              view_name = view_name[:-4] #Strip off '_dep'

            raise errors.UnexpectedDataError('Specified zone-view assignment '
                'does not exist for zone %s view %s' % (
                    record_data['zone_name'], view_name))
    finally:
      if( not current_transaction ):
        self.db_instance.EndTransaction()

    if( maintenance_mode and self.user_perms['user_access_level']
        != constants.ACCESS_LEVELS['dns_admin'] ):
      raise errors.MaintenanceError('Roster is currently under maintenance.')

    if( record_data is not None and record_data.has_key('zone_name') ):
      target_string = ' with %s on %s of type %s' % (record_data['target'],
                                          record_data['zone_name'],
                                          record_data['record_type'])

      user_group_perms = {}
      record_target = record_data['target']

      # Get user group permissions for record zone
      if( record_data['zone_name'] ):
        for origin in self.zone_origin_cache[record_data['zone_name']]:
          user_group_perms[origin] = []
          if( record_target == u'@' ):
            ip_address = helpers_lib.UnReverseIP(origin)
          else:
            ip_address = helpers_lib.UnReverseIP('%s.%s' % (
                record_target,
                origin))

          #Looking for permissions in the forward zones
          for zone in self.user_perms['forward_zones']:
            if( zone['zone_name'] == record_data['zone_name'] ):
              user_group_perms[origin].append(zone['group_permission'])

          #If we haven't found any, look in the reverse ranges
          if( user_group_perms[origin] == [] ):
            validation_instance = self.db_instance.data_validation_instance
            if( validation_instance.isIPv4IPAddress(ip_address) or
                validation_instance.isIPv6IPAddress(ip_address) ):
              for cidr in self.user_perms['reverse_ranges']:
                if( IPy.IP(cidr['cidr_block']).overlaps(ip_address) ):
                  user_group_perms[origin].append(cidr['group_permission'])
    else:
      target_string = ''
    auth_fail_string = ('User %s is not allowed to use %s%s' %
                        (self.user_name, method, target_string))

    #authorizing method
    if( self.abilities.has_key(method) ):
      method_hash = self.abilities[method]
      if( int(self.user_access_level) >= constants.ACCESS_LEVELS['dns_admin'] ):
        return

      if( method_hash['check'] ):
        # Secondary check - ensure the target is in a range delegated to
        # the user
        if( record_data is None ):
          raise errors.MissingDataTypeError(
              'No record data provided for access method '
              '%s' % method)
        elif( not record_data.has_key('zone_name') or
            record_data['zone_name'] is None or
            not record_data.has_key('view_name') or
            record_data['view_name'] is None or
            not record_data.has_key('target') or
            record_data['target'] is None or
            not record_data.has_key('record_type') or
            record_data['record_type'] is None or
            not record_data.has_key('record_args_dict') or
            record_data['record_args_dict'] is None ):
          raise errors.MissingDataTypeError(
              'Incomplete record data provided for access '
              'method %s' % method)
        # If user or less, check permission for zone origin
        elif( int(self.user_access_level) <= constants.ACCESS_LEVELS[
            'unlocked_user'] ):
          user_has_permission = False
          for origin in self.zone_origin_cache[record_data['zone_name']]:
            if( record_data['record_type'] in user_group_perms[origin] ):
              user_has_permission = True

          if( not user_has_permission ):
            raise errors.AuthorizationError(auth_fail_string)

        if( int(self.user_access_level) <
          constants.ACCESS_LEVELS['unlocked_user'] ):

          # if a or aaaa
          if( record_data['record_args_dict'].has_key(u'assignment_ip') ):
            ip = IPy.IP(record_data['record_args_dict'][u'assignment_ip'])
            for reverse_range in self.reverse_ranges:
              if( IPy.IP(reverse_range['cidr_block']).overlaps(ip) ):
                break
            else:
              raise errors.AuthorizationError(auth_fail_string)

          # if cname, mx, ns, or ptr
          elif( record_data['record_args_dict'].has_key(u'assignment_host') or
                record_data['record_args_dict'].has_key(u'mail_server') or
                record_data['record_args_dict'].has_key(u'name_server') ):
            hostname = None
            if( record_data['record_args_dict'].has_key(u'assignment_host') ):
              hostname = record_data['record_args_dict'][u'assignment_host']
            elif( record_data['record_args_dict'].has_key(u'mail_server') ):
              hostname = record_data['record_args_dict'][u'mail_server']
            elif( record_data['record_args_dict'].has_key(u'name_server') ):
              hostname = record_data['record_args_dict'][u'name_server']
            smallest_zone = hostname

            found = False
            while( smallest_zone ):
              for domain in self.zone_origin_cache:
                for origin in self.zone_origin_cache[domain]:
                  if( smallest_zone == origin ):
                    found = True
              if( not found ):
                try:
                  smallest_zone = smallest_zone.split('.', 1)[1]
                except IndexError:
                  break
              else:
                break
            if( not found ):
              raise errors.AuthorizationError(auth_fail_string)

            for zone in self.forward_zones:
              if( self.zone_origin_cache.has_key(zone['zone_name']) ):
                found = False
                for origin in self.zone_origin_cache[zone['zone_name']]:
                  if( smallest_zone == origin ):
                    found = True
                    break
                if( found ):
                  break
            else:
              raise errors.AuthorizationError(auth_fail_string)

        for forward_zone in self.forward_zones:
          if( record_data['zone_name'] == forward_zone['zone_name'] ):
            return

        # Can't find it in forward zones, maybe it's a reverse
        try:
          ip = IPy.IP(ip_address)

          # Good, we have an IP.  See if we hit any delegated ranges.
          for reverse_range in self.reverse_ranges:
            if( IPy.IP(reverse_range['cidr_block']).overlaps(ip) ):
              return

          # fail to find a matching IP range with appropriate perms
          self.log_instance.LogAction(self.user_name, function_name,
                                      current_args, False, current_transaction)
          raise errors.AuthorizationError(auth_fail_string)

        except ValueError:
          # fail to find a matching zone with appropriate perms
          self.log_instance.LogAction(self.user_name, function_name,
                                      current_args, False, current_transaction)
          raise errors.AuthorizationError(auth_fail_string)
      else:
        return
    else:
      # fail to find a matching method
      self.log_instance.LogAction(self.user_name, function_name,
                                  current_args, False, current_transaction)
      raise errors.AuthorizationError(auth_fail_string)