Exemple #1
0
class TokenModel(sql.ModelBase, sql.DictBase):
    __tablename__ = 'token'
    attributes = ['id', 'expires', 'user_id', 'trust_id']
    id = sql.Column(sql.String(64), primary_key=True)
    expires = sql.Column(sql.DateTime(), default=None)
    extra = sql.Column(sql.JsonBlob())
    valid = sql.Column(sql.Boolean(), default=True, nullable=False)
    user_id = sql.Column(sql.String(64))
    trust_id = sql.Column(sql.String(64))
    __table_args__ = (sql.Index('ix_token_expires', 'expires'),
                      sql.Index('ix_token_expires_valid', 'expires', 'valid'),
                      sql.Index('ix_token_user_id', 'user_id'),
                      sql.Index('ix_token_trust_id', 'trust_id'))
Exemple #2
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'), {})
Exemple #3
0
class RequestToken(sql.ModelBase, sql.DictBase):
    __tablename__ = 'request_token'
    attributes = ['id', 'request_secret',
                  'verifier', 'authorizing_user_id', 'requested_project_id',
                  'role_ids', 'consumer_id', 'expires_at']
    id = sql.Column(sql.String(64), primary_key=True, nullable=False)
    request_secret = sql.Column(sql.String(64), nullable=False)
    verifier = sql.Column(sql.String(64), nullable=True)
    authorizing_user_id = sql.Column(sql.String(64), nullable=True)
    requested_project_id = sql.Column(sql.String(64), nullable=False)
    role_ids = sql.Column(sql.Text(), nullable=True)
    consumer_id = sql.Column(sql.String(64), sql.ForeignKey('consumer.id'),
                             nullable=False, index=True)
    expires_at = sql.Column(sql.String(64), nullable=True)

    @classmethod
    def from_dict(cls, user_dict):
        return cls(**user_dict)

    def to_dict(self):
        return dict(self.items())
Exemple #4
0
class Password(sql.ModelBase, sql.DictBase):
    __tablename__ = 'password'
    attributes = ['id', 'local_user_id', 'password', 'created_at',
                  'expires_at']
    id = sql.Column(sql.Integer, primary_key=True)
    local_user_id = sql.Column(sql.Integer, sql.ForeignKey('local_user.id',
                               ondelete='CASCADE'))
    password = sql.Column(sql.String(128), nullable=True)
    # created_at default set here to safe guard in case it gets missed
    created_at = sql.Column(sql.DateTime, nullable=False,
                            default=datetime.datetime.utcnow)
    expires_at = sql.Column(sql.DateTime, nullable=True)
    self_service = sql.Column(sql.Boolean, default=False, nullable=False,
                              server_default='0')
Exemple #5
0
class AccessToken(sql.ModelBase, sql.DictBase):
    __tablename__ = 'access_token_oauth2'

    attributes = [
        'id', 'consumer_id', 'authorizing_user_id', 'expires_at', 'scopes',
        'refresh_token', 'valid', 'extra'
    ]

    id = sql.Column(sql.String(64), primary_key=True, nullable=False)
    consumer_id = sql.Column(sql.String(64),
                             sql.ForeignKey('consumer_oauth2.id'),
                             nullable=False,
                             index=True)
    # NOTE(garcianavalon) if the consumers uses the client credentials grant
    # there is no authorizing user, so it should be nullable.
    authorizing_user_id = sql.Column(sql.String(64), nullable=True)
    # TODO(garcianavalon) datetime type or similar?
    expires_at = sql.Column(sql.String(64), nullable=False)
    scopes = sql.Column(sql.JsonBlob(), nullable=True)
    refresh_token = sql.Column(sql.String(64), nullable=True)
    valid = sql.Column(sql.Boolean(), default=True, nullable=False)
    extra = sql.Column(sql.JsonBlob(), nullable=True)
Exemple #6
0
class Endpoint(sql.ModelBase, sql.DictBase):
    __tablename__ = 'endpoint'
    attributes = [
        'id', 'interface', 'region_id', 'service_id', 'url',
        'legacy_endpoint_id', 'enabled'
    ]
    id = sql.Column(sql.String(64), primary_key=True)
    legacy_endpoint_id = sql.Column(sql.String(64))
    interface = sql.Column(sql.String(8), nullable=False)
    region_id = sql.Column(sql.String(255),
                           sql.ForeignKey('region.id', ondelete='RESTRICT'),
                           nullable=True,
                           default=None)
    service_id = sql.Column(sql.String(64),
                            sql.ForeignKey('service.id'),
                            nullable=False)
    url = sql.Column(sql.Text(), nullable=False)
    enabled = sql.Column(sql.Boolean,
                         nullable=False,
                         default=True,
                         server_default=sqlalchemy.sql.expression.true())
    extra = sql.Column(sql.JsonBlob())
Exemple #7
0
class Password(sql.ModelBase, sql.ModelDictMixin):
    __tablename__ = 'password'
    attributes = ['id', 'local_user_id', 'password', 'password_hash',
                  'created_at', 'expires_at']
    id = sql.Column(sql.Integer, primary_key=True)
    local_user_id = sql.Column(sql.Integer, sql.ForeignKey('local_user.id',
                               ondelete='CASCADE'))
    # TODO(notmorgan): in the Q release the "password" field can be dropped as
    # long as data migration exists to move the hashes over to the
    # password_hash column if no value is in the password_hash column.
    password = sql.Column(sql.String(128), nullable=True)
    password_hash = sql.Column(sql.String(255), nullable=True)

    # created_at default set here to safe guard in case it gets missed
    created_at = sql.Column(sql.DateTime, nullable=False,
                            default=datetime.datetime.utcnow)
    expires_at = sql.Column(sql.DateTime, nullable=True)
    self_service = sql.Column(sql.Boolean, default=False, nullable=False,
                              server_default='0')
Exemple #8
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
Exemple #9
0
class RegisteredLimitModel(sql.ModelBase, sql.ModelDictMixin):
    __tablename__ = 'registered_limit'
    attributes = [
        'internal_id', 'id', 'service_id', 'region_id', 'resource_name',
        'default_limit', 'description'
    ]

    internal_id = sql.Column(sql.Integer, primary_key=True, nullable=False)
    id = sql.Column(sql.String(length=64), nullable=False, unique=True)
    service_id = sql.Column(sql.String(255), sql.ForeignKey('service.id'))
    region_id = sql.Column(sql.String(64),
                           sql.ForeignKey('region.id'),
                           nullable=True)
    resource_name = sql.Column(sql.String(255))
    default_limit = sql.Column(sql.Integer, nullable=False)
    description = sql.Column(sql.Text())

    def to_dict(self):
        ref = super(RegisteredLimitModel, self).to_dict()
        ref.pop('internal_id')
        return ref
Exemple #10
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'])
    )
Exemple #11
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',
                                 lazy='subquery',
                                 backref='local_user',
                                 order_by='Password.created_at')
    failed_auth_count = sql.Column(sql.Integer, nullable=True)
    failed_auth_at = sql.Column(sql.DateTime, nullable=True)
    __table_args__ = (sql.UniqueConstraint('domain_id', 'name'), {})
Exemple #12
0
class RegisteredLimitModel(sql.ModelBase, sql.ModelDictMixin):
    __tablename__ = 'registered_limit'
    attributes = [
        'id', 'service_id', 'region_id', 'resource_name', 'default_limit',
        'description'
    ]

    id = sql.Column(sql.String(length=64), primary_key=True)
    service_id = sql.Column(sql.String(255), sql.ForeignKey('service.id'))
    region_id = sql.Column(sql.String(64),
                           sql.ForeignKey('region.id'),
                           nullable=True)
    resource_name = sql.Column(sql.String(255))
    default_limit = sql.Column(sql.Integer, nullable=False)
    description = sql.Column(sql.Text())

    __table_args__ = (sqlalchemy.UniqueConstraint('service_id', 'region_id',
                                                  'resource_name'), )
Exemple #13
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'))
Exemple #14
0
class AccessToken(sql.ModelBase, sql.DictBase):
    __tablename__ = 'access_token'
    attributes = [
        'id', 'access_secret', 'authorizing_user_id', 'project_id',
        'requested_roles', 'consumer_id', 'expires_at'
    ]
    id = sql.Column(sql.String(64), primary_key=True, nullable=False)
    access_secret = sql.Column(sql.String(64), nullable=False)
    authorizing_user_id = sql.Column(sql.String(64),
                                     nullable=False,
                                     index=True)
    project_id = sql.Column(sql.String(64), nullable=False)
    requested_roles = sql.Column(sql.Text(), nullable=False)
    consumer_id = sql.Column(sql.String(64), nullable=False)
    expires_at = sql.Column(sql.String(64), nullable=True)

    @classmethod
    def from_dict(cls, user_dict):
        return cls(**user_dict)

    def to_dict(self):
        return dict(self.iteritems())
Exemple #15
0
class LimitModel(sql.ModelBase, sql.ModelDictMixin):
    __tablename__ = 'limit'
    attributes = [
        'id', 'project_id', 'service_id', 'region_id', 'resource_name',
        'resource_limit'
    ]

    id = sql.Column(sql.String(length=64), primary_key=True)
    project_id = sql.Column(sql.String(64), sql.ForeignKey('project.id'))
    service_id = sql.Column(sql.String(255))
    region_id = sql.Column(sql.String(64), nullable=True)
    resource_name = sql.Column(sql.String(255))
    resource_limit = sql.Column(sql.Integer, nullable=False)

    __table_args__ = (
        sqlalchemy.ForeignKeyConstraint(
            ['service_id', 'region_id', 'resource_name'], [
                'registered_limit.service_id', 'registered_limit.region_id',
                'registered_limit.resource_name'
            ]),
        sqlalchemy.UniqueConstraint('project_id', 'service_id', 'region_id',
                                    'resource_name'),
    )
Exemple #16
0
class TestModel(ModelBase, sql.ModelDictMixin):
    __tablename__ = 'testmodel'
    id = sql.Column(sql.String(64), primary_key=True)
    text = sql.Column(sql.String(64), nullable=False)
Exemple #17
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)
    enabled = sql.Column(sql.Boolean)
    extra = sql.Column(sql.JsonBlob())
    default_project_id = sql.Column(sql.String(64))
    local_user = orm.relationship('LocalUser',
                                  uselist=False,
                                  single_parent=True,
                                  lazy='subquery',
                                  cascade='all,delete-orphan',
                                  backref='user')
    federated_users = orm.relationship('FederatedUser',
                                       single_parent=True,
                                       lazy='subquery',
                                       cascade='all,delete-orphan',
                                       backref='user')

    # name property
    @hybrid_property
    def name(self):
        if self.local_user:
            return self.local_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 property
    @hybrid_property
    def password(self):
        if self.local_user and self.local_user.passwords:
            return self.local_user.passwords[0].password
        else:
            return None

    @password.setter
    def password(self, value):
        if not value:
            if self.local_user and self.local_user.passwords:
                self.local_user.passwords = []
        else:
            if not self.local_user:
                self.local_user = LocalUser()
            if not self.local_user.passwords:
                self.local_user.passwords.append(Password())
            self.local_user.passwords[0].password = value

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

    # domain_id property
    @hybrid_property
    def domain_id(self):
        if self.local_user:
            return self.local_user.domain_id
        else:
            return None

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

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

    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
Exemple #18
0
class User(sql.ModelBase, sql.DictBase):
    __tablename__ = 'user'
    attributes = [
        'id', 'name', 'domain_id', 'password', 'enabled', 'default_project_id',
        'password_expires_at'
    ]
    readonly_attributes = ['id', 'password_expires_at']
    id = sql.Column(sql.String(64), primary_key=True)
    _enabled = sql.Column('enabled', sql.Boolean)
    extra = sql.Column(sql.JsonBlob())
    default_project_id = sql.Column(sql.String(64))
    local_user = orm.relationship('LocalUser',
                                  uselist=False,
                                  single_parent=True,
                                  lazy='subquery',
                                  cascade='all,delete-orphan',
                                  backref='user')
    federated_users = orm.relationship('FederatedUser',
                                       single_parent=True,
                                       lazy='subquery',
                                       cascade='all,delete-orphan',
                                       backref='user')
    nonlocal_users = orm.relationship('NonLocalUser',
                                      single_parent=True,
                                      lazy='subquery',
                                      cascade='all,delete-orphan',
                                      backref='user')
    created_at = sql.Column(sql.DateTime, nullable=True)
    last_active_at = sql.Column(sql.Date, nullable=True)

    # name property
    @hybrid_property
    def name(self):
        if self.local_user:
            return self.local_user.name
        elif self.nonlocal_users:
            return self.nonlocal_users[0].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
    @hybrid_property
    def password_ref(self):
        """Return the current password."""
        if self.local_user and self.local_user.passwords:
            return self.local_user.passwords[-1]
        return None

    @hybrid_property
    def password(self):
        if self.password_ref:
            return self.password_ref.password
        return None

    @hybrid_property
    def password_created_at(self):
        if self.password_ref:
            return self.password_ref.created_at
        return None

    @hybrid_property
    def password_expires_at(self):
        if self.password_ref:
            return self.password_ref.expires_at
        return None

    @hybrid_property
    def password_is_expired(self):
        if self.password_expires_at:
            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
            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()
        new_password_ref.password = value
        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 _get_password_expires_at(self, created_at):
        expires_days = CONF.security_compliance.password_expires_days
        ignore_list = CONF.security_compliance.password_expires_ignore_user_ids
        if expires_days and (self.id not in ignore_list):
            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

    # domain_id property
    @hybrid_property
    def domain_id(self):
        if self.local_user:
            return self.local_user.domain_id
        elif self.nonlocal_users:
            return self.nonlocal_users[0].domain_id
        else:
            return None

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

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

    # enabled property
    @hybrid_property
    def enabled(self):
        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 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

    @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()
        password_expires_at_key = 'password_expires_at'
        if password_expires_at_key in user_dict:
            del new_dict[password_expires_at_key]
        return super(User, cls).from_dict(new_dict)
Exemple #19
0
class RevocationEvent(sql.ModelBase, sql.ModelDictMixin):
    __tablename__ = 'revocation_event'
    attributes = model.REVOKE_KEYS

    # The id field is not going to be exposed to the outside world.
    # It is, however, necessary for SQLAlchemy.
    id = sql.Column(sql.String(64), primary_key=True)
    domain_id = sql.Column(sql.String(64))
    project_id = sql.Column(sql.String(64))
    user_id = sql.Column(sql.String(64))
    role_id = sql.Column(sql.String(64))
    trust_id = sql.Column(sql.String(64))
    consumer_id = sql.Column(sql.String(64))
    access_token_id = sql.Column(sql.String(64))
    issued_before = sql.Column(sql.DateTime(), nullable=False)
    expires_at = sql.Column(sql.DateTime())
    revoked_at = sql.Column(sql.DateTime(), nullable=False)
Exemple #20
0
class Role(sql.ModelBase, sql.DictBase):
    __tablename__ = 'role'
    attributes = ['id', 'name']
    id = sql.Column(sql.String(64), primary_key=True)
    name = sql.Column(sql.String(64), unique=True, nullable=False)
    extra = sql.Column(sql.JsonBlob())
Exemple #21
0
class GroupProjectGrant(sql.ModelBase, BaseGrant):
    __tablename__ = 'group_project_metadata'
    group_id = sql.Column(sql.String(64), primary_key=True)
    project_id = sql.Column(sql.String(64), primary_key=True)
    data = sql.Column(sql.JsonBlob())
Exemple #22
0
class Role(sql.ModelBase, sql.DictBase):
    __tablename__ = 'role'
    id = sql.Column(sql.String(64), primary_key=True)
    name = sql.Column(sql.String(64), unique=True, nullable=False)
Exemple #23
0
class GroupDomainGrant(sql.ModelBase, BaseGrant):
    __tablename__ = 'group_domain_metadata'
    group_id = sql.Column(sql.String(64), primary_key=True)
    domain_id = sql.Column(sql.String(64), primary_key=True)
    data = sql.Column(sql.JsonBlob())
Exemple #24
0
class ProjectEndpoint(sql.ModelBase, sql.DictBase):
    """project-endpoint relationship table."""
    __tablename__ = 'project_endpoint'
    attributes = ['endpoint_id', 'project_id']
    endpoint_id = sql.Column(sql.String(64), primary_key=True, nullable=False)
    project_id = sql.Column(sql.String(64), primary_key=True, nullable=False)
Exemple #25
0
class ConfigRegister(sql.ModelBase, sql.ModelDictMixin):
    __tablename__ = 'config_register'
    type = sql.Column(sql.String(64), primary_key=True)
    domain_id = sql.Column(sql.String(64), nullable=False)
Exemple #26
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
Exemple #27
0
class TrustRole(sql.ModelBase):
    __tablename__ = 'trust_role'
    attributes = ['trust_id', 'role_id']
    trust_id = sql.Column(sql.String(64), primary_key=True, nullable=False)
    role_id = sql.Column(sql.String(64), primary_key=True, nullable=False)
Exemple #28
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)
    _enabled = sql.Column('enabled', sql.Boolean)
    extra = sql.Column(sql.JsonBlob())
    default_project_id = sql.Column(sql.String(64))
    local_user = orm.relationship('LocalUser', uselist=False,
                                  single_parent=True, lazy='subquery',
                                  cascade='all,delete-orphan', backref='user')
    federated_users = orm.relationship('FederatedUser',
                                       single_parent=True,
                                       lazy='subquery',
                                       cascade='all,delete-orphan',
                                       backref='user')
    nonlocal_users = orm.relationship('NonLocalUser',
                                      single_parent=True,
                                      lazy='subquery',
                                      cascade='all,delete-orphan',
                                      backref='user')
    created_at = sql.Column(sql.DateTime, nullable=True)
    last_active_at = sql.Column(sql.Date, nullable=True)

    # name property
    @hybrid_property
    def name(self):
        if self.local_user:
            return self.local_user.name
        elif self.nonlocal_users:
            return self.nonlocal_users[0].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
    @hybrid_property
    def password_ref(self):
        """Return the current password."""
        if self.local_user and self.local_user.passwords:
            return self.local_user.passwords[-1]
        return None

    @hybrid_property
    def password(self):
        if self.password_ref:
            return self.password_ref.password
        return None

    @hybrid_property
    def password_expires_at(self):
        if self.password_ref:
            return self.password_ref.expires_at
        return None

    @password.setter
    def password(self, value):
        now = datetime.datetime.utcnow()
        if not self.local_user:
            self.local_user = LocalUser()
        # 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()
        new_password_ref.password = value
        new_password_ref.created_at = now
        self.local_user.passwords.append(new_password_ref)

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

    # domain_id property
    @hybrid_property
    def domain_id(self):
        if self.local_user:
            return self.local_user.domain_id
        elif self.nonlocal_users:
            return self.nonlocal_users[0].domain_id
        else:
            return None

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

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

    # enabled property
    @hybrid_property
    def enabled(self):
        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()
        self._enabled = value

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

    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
Exemple #29
0
class LimitModel(sql.ModelBase, sql.ModelDictMixin):
    __tablename__ = 'limit'
    attributes = [
        'internal_id', 'id', 'project_id', 'service_id', 'region_id',
        'resource_name', 'resource_limit', 'description', 'registered_limit_id'
    ]

    # TODO(wxy): Drop "service_id", "region_id" and "resource_name" columns
    # in T release.
    internal_id = sql.Column(sql.Integer, primary_key=True, nullable=False)
    id = sql.Column(sql.String(length=64), nullable=False, unique=True)
    project_id = sql.Column(sql.String(64))
    _service_id = sql.Column('service_id', sql.String(255))
    _region_id = sql.Column('region_id', sql.String(64), nullable=True)
    _resource_name = sql.Column('resource_name', sql.String(255))
    resource_limit = sql.Column(sql.Integer, nullable=False)
    description = sql.Column(sql.Text())
    registered_limit_id = sql.Column(sql.String(64),
                                     sql.ForeignKey('registered_limit.id'))

    registered_limit = sqlalchemy.orm.relationship('RegisteredLimitModel')

    @hybrid_property
    def service_id(self):
        if self.registered_limit:
            return self.registered_limit.service_id
        return self._service_id

    @service_id.setter
    def service_id(self, value):
        self._service_id = value

    @service_id.expression
    def service_id(self):
        return LimitModel._service_id

    @hybrid_property
    def region_id(self):
        if self.registered_limit:
            return self.registered_limit.region_id
        return self._region_id

    @region_id.setter
    def region_id(self, value):
        self._region_id = value

    @region_id.expression
    def region_id(self):
        return LimitModel._region_id

    @hybrid_property
    def resource_name(self):
        if self.registered_limit:
            return self.registered_limit.resource_name
        return self._resource_name

    @resource_name.setter
    def resource_name(self, value):
        self._resource_name = value

    @resource_name.expression
    def resource_name(self):
        return LimitModel._resource_name

    @classmethod
    def from_dict(cls, limit):
        obj = super(LimitModel, cls).from_dict(limit)
        with sql.session_for_read() as session:
            query = session.query(RegisteredLimitModel).filter_by(
                id=obj.registered_limit_id)
            obj.registered_limit = query.first()
        return obj

    def to_dict(self):
        ref = super(LimitModel, self).to_dict()
        ref.pop('internal_id')
        ref.pop('registered_limit_id')
        return ref
Exemple #30
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