Example #1
0
class Group(sql.ModelBase, sql.ModelDictMixinWithExtras):
    __tablename__ = 'group'
    attributes = ['id', 'name', 'domain_id', 'description']
    id = sql.Column(sql.String(64), primary_key=True)
    name = sql.Column(sql.String(64), nullable=False)
    domain_id = sql.Column(sql.String(64), nullable=False)
    description = sql.Column(sql.Text())
    extra = sql.Column(sql.JsonBlob())
    # Unique constraint across two columns to create the separation
    # rather than just only 'name' being unique
    __table_args__ = (sql.UniqueConstraint('domain_id', 'name'), )
Example #2
0
class LocalUser(sql.ModelBase, sql.DictBase):
    __tablename__ = 'local_user'
    attributes = ['id', 'user_id', 'domain_id', 'name']
    id = sql.Column(sql.Integer, primary_key=True)
    user_id = sql.Column(sql.String(64), sql.ForeignKey('user.id',
                         ondelete='CASCADE'), unique=True)
    domain_id = sql.Column(sql.String(64), nullable=False)
    name = sql.Column(sql.String(255), nullable=False)
    passwords = orm.relationship('Password', single_parent=True,
                                 cascade='all,delete-orphan',
                                 backref='local_user')
    __table_args__ = (sql.UniqueConstraint('domain_id', 'name'), {})
Example #3
0
class LocalUser(sql.ModelBase, sql.ModelDictMixin):
    __tablename__ = 'local_user'
    attributes = ['id', 'user_id', 'domain_id', 'name']
    id = sql.Column(sql.Integer, primary_key=True)
    user_id = sql.Column(sql.String(64))
    domain_id = sql.Column(sql.String(64), nullable=False)
    name = sql.Column(sql.String(255), nullable=False)
    passwords = orm.relationship('Password',
                                 single_parent=True,
                                 cascade='all,delete-orphan',
                                 lazy='joined',
                                 backref='local_user',
                                 order_by='Password.created_at_int')
    failed_auth_count = sql.Column(sql.Integer, nullable=True)
    failed_auth_at = sql.Column(sql.DateTime, nullable=True)
    __table_args__ = (
        sql.UniqueConstraint('user_id'),
        sql.UniqueConstraint('domain_id', 'name'),
        sqlalchemy.ForeignKeyConstraint(['user_id', 'domain_id'],
                                        ['user.id', 'user.domain_id'],
                                        onupdate='CASCADE', ondelete='CASCADE')
    )
Example #4
0
class Project(sql.ModelBase, sql.DictBase):
    __tablename__ = 'project'
    attributes = ['id', 'name', 'domain_id', 'description', 'enabled']
    id = sql.Column(sql.String(64), primary_key=True)
    name = sql.Column(sql.String(64), nullable=False)
    domain_id = sql.Column(sql.String(64), sql.ForeignKey('domain.id'),
                           nullable=False)
    description = sql.Column(sql.Text())
    enabled = sql.Column(sql.Boolean)
    extra = sql.Column(sql.JsonBlob())
    # Unique constraint across two columns to create the separation
    # rather than just only 'name' being unique
    __table_args__ = (sql.UniqueConstraint('domain_id', 'name'), {})
Example #5
0
class NonLocalUser(sql.ModelBase, sql.ModelDictMixin):
    """SQL data model for nonlocal users (LDAP and custom)."""

    __tablename__ = 'nonlocal_user'
    attributes = ['domain_id', 'name', 'user_id']
    domain_id = sql.Column(sql.String(64), primary_key=True)
    name = sql.Column(sql.String(255), primary_key=True)
    user_id = sql.Column(sql.String(64))
    __table_args__ = (
        sql.UniqueConstraint('user_id'),
        sqlalchemy.ForeignKeyConstraint(
            ['user_id', 'domain_id'], ['user.id', 'user.domain_id'],
            onupdate='CASCADE', ondelete='CASCADE'),)
Example #6
0
class ProjectTag(sql.ModelBase, sql.ModelDictMixin):
    def to_dict(self):
        d = super(ProjectTag, self).to_dict()
        return d

    __tablename__ = 'project_tag'
    attributes = ['project_id', 'name']
    project_id = sql.Column(sql.String(64),
                            sql.ForeignKey('project.id', ondelete='CASCADE'),
                            nullable=False,
                            primary_key=True)
    name = sql.Column(sql.Unicode(255), nullable=False, primary_key=True)
    __table_args__ = (sql.UniqueConstraint('project_id', 'name'), )
Example #7
0
class RoleTable(sql.ModelBase, sql.ModelDictMixinWithExtras):

    def to_dict(self, include_extra_dict=False):
        d = super(RoleTable, self).to_dict(
            include_extra_dict=include_extra_dict)
        if d['domain_id'] == base.NULL_DOMAIN_ID:
            d['domain_id'] = None
        # NOTE(notmorgan): Eventually it may make sense to drop the empty
        # option dict creation to the superclass (if enough models use it)
        d['options'] = resource_options.ref_mapper_to_dict_options(self)
        return d

    @classmethod
    def from_dict(cls, role_dict):
        if 'domain_id' in role_dict and role_dict['domain_id'] is None:
            new_dict = role_dict.copy()
            new_dict['domain_id'] = base.NULL_DOMAIN_ID
        else:
            new_dict = role_dict
        # TODO(morgan): move this functionality to a common location
        resource_options = {}
        options = new_dict.pop('options', {})
        for opt in cls.resource_options_registry.options:
            if opt.option_name in options:
                opt_value = options[opt.option_name]
                # NOTE(notmorgan): None is always a valid type
                if opt_value is not None:
                    opt.validator(opt_value)
                resource_options[opt.option_id] = opt_value
        role_obj = super(RoleTable, cls).from_dict(new_dict)
        setattr(role_obj, '_resource_options', resource_options)
        return role_obj

    __tablename__ = 'role'
    attributes = ['id', 'name', 'domain_id', 'description']
    resource_options_registry = ro.ROLE_OPTIONS_REGISTRY
    id = sql.Column(sql.String(64), primary_key=True)
    name = sql.Column(sql.String(255), nullable=False)
    domain_id = sql.Column(sql.String(64), nullable=False,
                           server_default=base.NULL_DOMAIN_ID)
    description = sql.Column(sql.String(255), nullable=True)
    extra = sql.Column(sql.JsonBlob())
    _resource_option_mapper = orm.relationship(
        'RoleOption',
        single_parent=True,
        cascade='all,delete,delete-orphan',
        lazy='subquery',
        backref='role',
        collection_class=collections.attribute_mapped_collection('option_id')
    )
    __table_args__ = (sql.UniqueConstraint('name', 'domain_id'),)
Example #8
0
class IDMapping(sql.ModelBase, sql.ModelDictMixin):
    __tablename__ = 'id_mapping'
    public_id = sql.Column(sql.String(64), primary_key=True)
    domain_id = sql.Column(sql.String(64), nullable=False)
    local_id = sql.Column(sql.String(64), nullable=False)
    # NOTE(henry-nash): Postgres requires a name to be defined for an Enum
    entity_type = sql.Column(sql.Enum(identity_mapping.EntityType.USER,
                                      identity_mapping.EntityType.GROUP,
                                      name='entity_type'),
                             nullable=False)
    # Unique constraint to ensure you can't store more than one mapping to the
    # same underlying values
    __table_args__ = (sql.UniqueConstraint('domain_id', 'local_id',
                                           'entity_type'), )
Example #9
0
class Group(sql.ModelBase, sql.ModelDictMixinWithExtras):
    __tablename__ = 'group'
    attributes = ['id', 'name', 'domain_id', 'description']
    id = sql.Column(sql.String(64), primary_key=True)
    name = sql.Column(sql.String(64), nullable=False)
    domain_id = sql.Column(sql.String(64), nullable=False)
    description = sql.Column(sql.Text())
    extra = sql.Column(sql.JsonBlob())
    expiring_user_group_memberships = orm.relationship(
        'ExpiringUserGroupMembership',
        cascade='all, delete-orphan',
        backref="group")
    # Unique constraint across two columns to create the separation
    # rather than just only 'name' being unique
    __table_args__ = (sql.UniqueConstraint('domain_id', 'name'), )
Example #10
0
class Permission(sql.ModelBase, sql.ModelDictMixin):
    __tablename__ = 'permission_fiware'
    __table_args__ = (sql.UniqueConstraint('name', 'application_id'), {'extend_existing': True})
    attributes = ['id', 'name', 'is_internal', 'application_id', 'action'
                  'resource', 'xml']
    id = sql.Column(sql.String(64), primary_key=True, nullable=False)
    name = sql.Column(sql.String(64), nullable=False)
    is_internal = sql.Column(sql.Boolean(), default=False, nullable=False)
    application_id = sql.Column(
        sql.String(64),
        sql.ForeignKey('consumer_oauth2.id'),
        nullable=False,
        index=True)
    action = sql.Column(sql.String(10), nullable=True)
    resource = sql.Column(sql.String(256), nullable=True)
    xml = sql.Column(sql.Text(), nullable=True)
Example #11
0
class AccessRuleModel(sql.ModelBase, sql.ModelDictMixin):
    __tablename__ = 'access_rule'
    attributes = ['external_id', 'user_id', 'service', 'path', 'method']
    id = sql.Column(sql.Integer, primary_key=True, nullable=False)
    external_id = sql.Column(sql.String(64), index=True, unique=True)
    user_id = sql.Column(sql.String(64), index=True)
    service = sql.Column(sql.String(64))
    path = sql.Column(sql.String(128))
    method = sql.Column(sql.String(16))
    __table_args__ = (sql.UniqueConstraint(
        'user_id',
        'service',
        'path',
        'method',
        name='duplicate_access_rule_for_user_constraint'), )
    application_credential = sqlalchemy.orm.relationship(
        'ApplicationCredentialAccessRuleModel',
        backref=sqlalchemy.orm.backref('access_rule'))
Example #12
0
class FederatedUser(sql.ModelBase, sql.ModelDictMixin):
    __tablename__ = 'federated_user'
    attributes = ['id', 'user_id', 'idp_id', 'protocol_id', 'unique_id',
                  'display_name']
    id = sql.Column(sql.Integer, primary_key=True)
    user_id = sql.Column(sql.String(64), sql.ForeignKey('user.id',
                                                        ondelete='CASCADE'))
    idp_id = sql.Column(sql.String(64), sql.ForeignKey('identity_provider.id',
                                                       ondelete='CASCADE'))
    protocol_id = sql.Column(sql.String(64), nullable=False)
    unique_id = sql.Column(sql.String(255), nullable=False)
    display_name = sql.Column(sql.String(255), nullable=True)
    __table_args__ = (
        sql.UniqueConstraint('idp_id', 'protocol_id', 'unique_id'),
        sqlalchemy.ForeignKeyConstraint(['protocol_id', 'idp_id'],
                                        ['federation_protocol.id',
                                         'federation_protocol.idp_id'])
    )
Example #13
0
class TrustModel(sql.ModelBase, sql.DictBase):
    __tablename__ = 'trust'
    attributes = ['id', 'trustor_user_id', 'trustee_user_id',
                  'project_id', 'impersonation', 'expires_at',
                  'remaining_uses', 'deleted_at']
    id = sql.Column(sql.String(64), primary_key=True)
    # user id of owner
    trustor_user_id = sql.Column(sql.String(64), nullable=False,)
    # user_id of user allowed to consume this preauth
    trustee_user_id = sql.Column(sql.String(64), nullable=False)
    project_id = sql.Column(sql.String(64))
    impersonation = sql.Column(sql.Boolean, nullable=False)
    deleted_at = sql.Column(sql.DateTime)
    expires_at = sql.Column(sql.DateTime)
    remaining_uses = sql.Column(sql.Integer, nullable=True)
    extra = sql.Column(sql.JsonBlob())
    __table_args__ = (sql.UniqueConstraint(
                      'trustor_user_id', 'trustee_user_id', 'project_id',
                      'impersonation', 'expires_at',
                      name='duplicate_trust_constraint'),)
Example #14
0
class User(sql.ModelBase, sql.DictBase):
    __tablename__ = 'user'
    attributes = ['id', 'name', 'domain_id', 'password', 'enabled',
                  'default_project_id']
    id = sql.Column(sql.String(64), primary_key=True)
    name = sql.Column(sql.String(255), nullable=False)
    domain_id = sql.Column(sql.String(64), nullable=False)
    password = sql.Column(sql.String(128))
    enabled = sql.Column(sql.Boolean)
    extra = sql.Column(sql.JsonBlob())
    default_project_id = sql.Column(sql.String(64))
    # Unique constraint across two columns to create the separation
    # rather than just only 'name' being unique
    __table_args__ = (sql.UniqueConstraint('domain_id', 'name'), {})

    def to_dict(self, include_extra_dict=False):
        d = super(User, self).to_dict(include_extra_dict=include_extra_dict)
        if 'default_project_id' in d and d['default_project_id'] is None:
            del d['default_project_id']
        return d
Example #15
0
class TrustModel(sql.ModelBase, sql.ModelDictMixinWithExtras):
    __tablename__ = 'trust'
    attributes = [
        'id', 'trustor_user_id', 'trustee_user_id', 'project_id',
        'impersonation', 'expires_at', 'remaining_uses', 'deleted_at',
        'redelegated_trust_id', 'redelegation_count'
    ]
    id = sql.Column(sql.String(64), primary_key=True)
    # user id of owner
    trustor_user_id = sql.Column(
        sql.String(64),
        nullable=False,
    )
    # user_id of user allowed to consume this preauth
    trustee_user_id = sql.Column(sql.String(64), nullable=False)
    project_id = sql.Column(sql.String(64))
    impersonation = sql.Column(sql.Boolean, nullable=False)
    deleted_at = sql.Column(sql.DateTime)
    _expires_at = sql.Column('expires_at', sql.DateTime)
    expires_at_int = sql.Column(sql.DateTimeInt(), nullable=True)
    remaining_uses = sql.Column(sql.Integer, nullable=True)
    redelegated_trust_id = sql.Column(sql.String(64), nullable=True)
    redelegation_count = sql.Column(sql.Integer, nullable=True)
    extra = sql.Column(sql.JsonBlob())
    __table_args__ = (sql.UniqueConstraint(
        'trustor_user_id',
        'trustee_user_id',
        'project_id',
        'impersonation',
        'expires_at',
        name='duplicate_trust_constraint'), )

    @hybrid_property
    def expires_at(self):
        return self.expires_at_int or self._expires_at

    @expires_at.setter
    def expires_at(self, value):
        self._expires_at = value
        self.expires_at_int = value
Example #16
0
class FederationProtocolModel(sql.ModelBase, sql.DictBase):
    __tablename__ = 'federation_protocol'
    attributes = ['id', 'idp_id', 'mapping_id']
    mutable_attributes = frozenset(['mapping_id'])

    id = sql.Column(sql.String(64), primary_key=True)
    idp_id = sql.Column(sql.String(64), sql.ForeignKey('identity_provider.id',
                        ondelete='CASCADE'), primary_key=True)
    mapping_id = sql.Column(sql.String(64), nullable=False)
    __table_args__ = (sql.UniqueConstraint('id', 'idp_id'), dict())

    @classmethod
    def from_dict(cls, dictionary):
        new_dictionary = dictionary.copy()
        return cls(**new_dictionary)

    def to_dict(self):
        """Return a dictionary with model's attributes."""
        d = dict()
        for attr in self.__class__.attributes:
            d[attr] = getattr(self, attr)
        return d
Example #17
0
class ApplicationCredentialModel(sql.ModelBase, sql.ModelDictMixin):
    __tablename__ = 'application_credential'
    attributes = [
        'internal_id', 'id', 'name', 'secret_hash', 'description', 'user_id',
        'project_id', 'system', 'expires_at', 'unrestricted'
    ]
    internal_id = sql.Column(sql.Integer, primary_key=True, nullable=False)
    id = sql.Column(sql.String(64), nullable=False)
    name = sql.Column(sql.String(255), nullable=False)
    secret_hash = sql.Column(sql.String(255), nullable=False)
    description = sql.Column(sql.Text())
    user_id = sql.Column(sql.String(64), nullable=False)
    project_id = sql.Column(sql.String(64), nullable=True)
    system = sql.Column(sql.String(64), nullable=True)
    expires_at = sql.Column(sql.DateTimeInt())
    unrestricted = sql.Column(sql.Boolean)
    __table_args__ = (sql.UniqueConstraint(
        'name', 'user_id', name='duplicate_app_cred_constraint'), )

    roles = sqlalchemy.orm.relationship(
        'ApplicationCredentialRoleModel',
        backref=sqlalchemy.orm.backref('application_credential'),
        cascade='all, delete-orphan')
Example #18
0
class Project(sql.ModelBase, sql.ModelDictMixinWithExtras):
    # NOTE(henry-nash): From the manager and above perspective, the domain_id
    # is nullable.  However, to ensure uniqueness in multi-process
    # configurations, it is better to still use the sql uniqueness constraint.
    # Since the support for a nullable component of a uniqueness constraint
    # across different sql databases is mixed, we instead store a special value
    # to represent null, as defined in NULL_DOMAIN_ID above.

    def to_dict(self, include_extra_dict=False):
        d = super(Project, self).to_dict(
            include_extra_dict=include_extra_dict)
        if d['domain_id'] == base.NULL_DOMAIN_ID:
            d['domain_id'] = None
        # NOTE(notmorgan): Eventually it may make sense to drop the empty
        # option dict creation to the superclass (if enough models use it)
        d['options'] = resource_options.ref_mapper_to_dict_options(self)
        return d

    @classmethod
    def from_dict(cls, project_dict):
        new_dict = project_dict.copy()
        # TODO(morgan): move this functionality to a common location
        resource_options = {}
        options = new_dict.pop('options', {})
        for opt in cls.resource_options_registry.options:
            if opt.option_name in options:
                opt_value = options[opt.option_name]
                # NOTE(notmorgan): None is always a valid type
                if opt_value is not None:
                    opt.validator(opt_value)
                resource_options[opt.option_id] = opt_value
        project_obj = super(Project, cls).from_dict(new_dict)
        setattr(project_obj, '_resource_options', resource_options)
        return project_obj

    __tablename__ = 'project'
    attributes = ['id', 'name', 'domain_id', 'description', 'enabled',
                  'parent_id', 'is_domain', 'tags']
    resource_options_registry = ro.PROJECT_OPTIONS_REGISTRY
    id = sql.Column(sql.String(64), primary_key=True)
    name = sql.Column(sql.String(64), nullable=False)
    domain_id = sql.Column(sql.String(64), sql.ForeignKey('project.id'),
                           nullable=False)
    description = sql.Column(sql.Text())
    enabled = sql.Column(sql.Boolean)
    extra = sql.Column(sql.JsonBlob())
    parent_id = sql.Column(sql.String(64), sql.ForeignKey('project.id'))
    is_domain = sql.Column(sql.Boolean, default=False, nullable=False,
                           server_default='0')
    _tags = orm.relationship(
        'ProjectTag',
        single_parent=True,
        lazy='subquery',
        cascade='all,delete-orphan',
        backref='project',
        primaryjoin='and_(ProjectTag.project_id==Project.id)'
    )
    _resource_option_mapper = orm.relationship(
        'ProjectOption',
        single_parent=True,
        cascade='all,delete,delete-orphan',
        lazy='subquery',
        backref='project',
        collection_class=collections.attribute_mapped_collection('option_id')
    )

    # Unique constraint across two columns to create the separation
    # rather than just only 'name' being unique
    __table_args__ = (sql.UniqueConstraint('domain_id', 'name'),)

    @property
    def tags(self):
        if self._tags:
            return [tag.name for tag in self._tags]
        return []

    @tags.setter
    def tags(self, values):
        new_tags = []
        for tag in values:
            tag_ref = ProjectTag()
            tag_ref.project_id = self.id
            tag_ref.name = text_type(tag)
            new_tags.append(tag_ref)
        self._tags = new_tags
Example #19
0
class User(sql.ModelBase, sql.ModelDictMixinWithExtras):
    __tablename__ = 'user'
    attributes = ['id', 'name', 'domain_id', 'password', 'enabled',
                  'default_project_id', 'password_expires_at']
    readonly_attributes = ['id', 'password_expires_at', 'password']
    resource_options_registry = iro.USER_OPTIONS_REGISTRY
    id = sql.Column(sql.String(64), primary_key=True)
    domain_id = sql.Column(sql.String(64), nullable=False)
    _enabled = sql.Column('enabled', sql.Boolean)
    extra = sql.Column(sql.JsonBlob())
    default_project_id = sql.Column(sql.String(64), index=True)
    _resource_option_mapper = orm.relationship(
        'UserOption',
        single_parent=True,
        cascade='all,delete,delete-orphan',
        lazy='subquery',
        backref='user',
        collection_class=collections.attribute_mapped_collection('option_id'))
    local_user = orm.relationship('LocalUser', uselist=False,
                                  single_parent=True, lazy='joined',
                                  cascade='all,delete-orphan', backref='user')
    federated_users = orm.relationship('FederatedUser',
                                       single_parent=True,
                                       lazy='joined',
                                       cascade='all,delete-orphan',
                                       backref='user')
    nonlocal_user = orm.relationship('NonLocalUser',
                                     uselist=False,
                                     single_parent=True,
                                     lazy='joined',
                                     cascade='all,delete-orphan',
                                     backref='user')
    created_at = sql.Column(sql.DateTime, nullable=True)
    last_active_at = sql.Column(sql.Date, nullable=True)
    # unique constraint needed here to support composite fk constraints
    __table_args__ = (sql.UniqueConstraint('id', 'domain_id'), {})

    # NOTE(stevemar): we use a hybrid property here because we leverage the
    # expression method, see `@name.expression` and `LocalUser.name` below.
    @hybrid_property
    def name(self):
        """Return the current user name."""
        if self.local_user:
            return self.local_user.name
        elif self.nonlocal_user:
            return self.nonlocal_user.name
        elif self.federated_users:
            return self.federated_users[0].display_name
        else:
            return None

    @name.setter
    def name(self, value):
        if not self.local_user:
            self.local_user = LocalUser()
        self.local_user.name = value

    @name.expression
    def name(cls):
        return LocalUser.name

    # password properties
    @property
    def password_ref(self):
        """Return the current password ref."""
        if self.local_user and self.local_user.passwords:
            return self.local_user.passwords[-1]
        return None

    # NOTE(stevemar): we use a hybrid property here because we leverage the
    # expression method, see `@password.expression` and `Password.password`
    # below.
    @hybrid_property
    def password(self):
        """Return the current password."""
        if self.password_ref:
            return self.password_ref.password_hash
        return None

    @property
    def password_created_at(self):
        """Return when password was created at."""
        if self.password_ref:
            return self.password_ref.created_at
        return None

    @property
    def password_expires_at(self):
        """Return when password expires at."""
        if self.password_ref:
            return self.password_ref.expires_at
        return None

    @property
    def password_is_expired(self):
        """Return whether password is expired or not."""
        if self.password_expires_at and not self._password_expiry_exempt():
            return datetime.datetime.utcnow() >= self.password_expires_at
        return False

    @password.setter
    def password(self, value):
        now = datetime.datetime.utcnow()
        if not self.local_user:
            self.local_user = LocalUser()
        # truncate extra passwords
        if self.local_user.passwords:
            unique_cnt = CONF.security_compliance.unique_last_password_count
            unique_cnt = unique_cnt + 1 if unique_cnt == 0 else unique_cnt
            self.local_user.passwords = self.local_user.passwords[-unique_cnt:]
        # set all previous passwords to be expired
        for ref in self.local_user.passwords:
            if not ref.expires_at or ref.expires_at > now:
                ref.expires_at = now
        new_password_ref = Password()

        hashed_passwd = None
        if value is not None:
            # NOTE(notmorgan): hash the passwords, never directly bind the
            # "value" in the unhashed form to hashed_passwd to ensure the
            # unhashed password cannot end up in the db. If an unhashed
            # password ends up in the DB, it cannot be used for auth, it is
            # however incorrect and could leak user credentials (due to users
            # doing insecure things such as sharing passwords across
            # different systems) to unauthorized parties.
            hashed_passwd = password_hashing.hash_password(value)

        new_password_ref.password_hash = hashed_passwd
        new_password_ref.created_at = now
        new_password_ref.expires_at = self._get_password_expires_at(now)
        self.local_user.passwords.append(new_password_ref)

    def _password_expiry_exempt(self):
        # Get the IGNORE_PASSWORD_EXPIRY_OPT value from the user's
        # option_mapper.
        return getattr(
            self.get_resource_option(iro.IGNORE_PASSWORD_EXPIRY_OPT.option_id),
            'option_value',
            False)

    def _get_password_expires_at(self, created_at):
        expires_days = CONF.security_compliance.password_expires_days
        if not self._password_expiry_exempt():
            if expires_days:
                expired_date = (created_at +
                                datetime.timedelta(days=expires_days))
                return expired_date.replace(microsecond=0)
        return None

    @password.expression
    def password(cls):
        return Password.password_hash

    # NOTE(stevemar): we use a hybrid property here because we leverage the
    # expression method, see `@enabled.expression` and `User._enabled` below.
    @hybrid_property
    def enabled(self):
        """Return whether user is enabled or not."""
        if self._enabled:
            max_days = (
                CONF.security_compliance.disable_user_account_days_inactive)
            last_active = self.last_active_at
            if not last_active and self.created_at:
                last_active = self.created_at.date()
            if max_days and last_active:
                now = datetime.datetime.utcnow().date()
                days_inactive = (now - last_active).days
                if days_inactive >= max_days:
                    self._enabled = False
        return self._enabled

    @enabled.setter
    def enabled(self, value):
        if (value and
                CONF.security_compliance.disable_user_account_days_inactive):
            self.last_active_at = datetime.datetime.utcnow().date()
        if value and self.local_user:
            self.local_user.failed_auth_count = 0
            self.local_user.failed_auth_at = None
        self._enabled = value

    @enabled.expression
    def enabled(cls):
        return User._enabled

    def get_resource_option(self, option_id):
        if option_id in self._resource_option_mapper.keys():
            return self._resource_option_mapper[option_id]
        return None

    def to_dict(self, include_extra_dict=False):
        d = super(User, self).to_dict(include_extra_dict=include_extra_dict)
        if 'default_project_id' in d and d['default_project_id'] is None:
            del d['default_project_id']
        # NOTE(notmorgan): Eventually it may make sense to drop the empty
        # option dict creation to the superclass (if enough models use it)
        d['options'] = resource_options.ref_mapper_to_dict_options(self)
        return d

    @classmethod
    def from_dict(cls, user_dict):
        """Override from_dict to remove password_expires_at attribute.

        Overriding this method to remove password_expires_at attribute to
        support update_user and unit tests where password_expires_at
        inadvertently gets added by calling to_dict followed by from_dict.

        :param user_dict: User entity dictionary
        :returns User: User object

        """
        new_dict = user_dict.copy()
        resource_options = {}
        options = new_dict.pop('options', {})
        password_expires_at_key = 'password_expires_at'
        if password_expires_at_key in user_dict:
            del new_dict[password_expires_at_key]
        for opt in cls.resource_options_registry.options:
            if opt.option_name in options:
                opt_value = options[opt.option_name]
                # NOTE(notmorgan): None is always a valid type
                if opt_value is not None:
                    opt.validator(opt_value)
                resource_options[opt.option_id] = opt_value
        user_obj = super(User, cls).from_dict(new_dict)
        setattr(user_obj, '_resource_options', resource_options)
        return user_obj
Example #20
0
class Project(sql.ModelBase, sql.ModelDictMixinWithExtras):
    # NOTE(henry-nash): From the manager and above perspective, the domain_id
    # is nullable.  However, to ensure uniqueness in multi-process
    # configurations, it is better to still use the sql uniqueness constraint.
    # Since the support for a nullable component of a uniqueness constraint
    # across different sql databases is mixed, we instead store a special value
    # to represent null, as defined in NULL_DOMAIN_ID above.

    def to_dict(self, include_extra_dict=False):
        d = super(Project, self).to_dict(include_extra_dict=include_extra_dict)
        if d['domain_id'] == base.NULL_DOMAIN_ID:
            d['domain_id'] = None
        return d

    __tablename__ = 'project'
    attributes = [
        'id', 'name', 'domain_id', 'description', 'enabled', 'parent_id',
        'is_domain', 'tags'
    ]
    id = sql.Column(sql.String(64), primary_key=True)
    name = sql.Column(sql.String(64), nullable=False)
    domain_id = sql.Column(sql.String(64),
                           sql.ForeignKey('project.id'),
                           nullable=False)
    description = sql.Column(sql.Text())
    enabled = sql.Column(sql.Boolean)
    extra = sql.Column(sql.JsonBlob())
    parent_id = sql.Column(sql.String(64), sql.ForeignKey('project.id'))
    is_domain = sql.Column(sql.Boolean,
                           default=False,
                           nullable=False,
                           server_default='0')
    _tags = orm.relationship(
        'ProjectTag',
        single_parent=True,
        lazy='subquery',
        cascade='all,delete-orphan',
        backref='project',
        primaryjoin='and_(ProjectTag.project_id==Project.id)')

    # Unique constraint across two columns to create the separation
    # rather than just only 'name' being unique
    __table_args__ = (sql.UniqueConstraint('domain_id', 'name'), )

    @hybrid_property
    def tags(self):
        if self._tags:
            return [tag.name for tag in self._tags]
        return []

    @tags.setter
    def tags(self, values):
        new_tags = []
        for tag in values:
            tag_ref = ProjectTag()
            tag_ref.project_id = self.id
            tag_ref.name = tag
            new_tags.append(tag_ref)
        self._tags = new_tags

    @tags.expression
    def tags(cls):
        return ProjectTag.name