"Fossies" - the Fresh Open Source Software Archive

Member "keystone-18.0.0/keystone/identity/shadow_backends/sql.py" (14 Oct 2020, 10921 Bytes) of package /linux/misc/openstack/keystone-18.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "sql.py": 17.0.0_vs_18.0.0.

    1 # Licensed under the Apache License, Version 2.0 (the "License"); you may
    2 # not use this file except in compliance with the License. You may obtain
    3 # a copy of the License at
    4 #
    5 #      http://www.apache.org/licenses/LICENSE-2.0
    6 #
    7 # Unless required by applicable law or agreed to in writing, software
    8 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    9 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   10 # License for the specific language governing permissions and limitations
   11 # under the License.
   12 
   13 import copy
   14 import datetime
   15 import sqlalchemy
   16 
   17 from oslo_config import cfg
   18 from oslo_db import api as oslo_db_api
   19 
   20 from keystone.common import provider_api
   21 from keystone.common import sql
   22 from keystone import exception
   23 from keystone.identity.backends import base as identity_base
   24 from keystone.identity.backends import sql_model as model
   25 from keystone.identity.shadow_backends import base
   26 
   27 
   28 CONF = cfg.CONF
   29 PROVIDERS = provider_api.ProviderAPIs
   30 
   31 
   32 class ShadowUsers(base.ShadowUsersDriverBase):
   33     @sql.handle_conflicts(conflict_type='federated_user')
   34     def create_federated_user(self, domain_id, federated_dict, email=None):
   35 
   36         local_entity = {'domain_id': domain_id,
   37                         'local_id': federated_dict['unique_id'],
   38                         'entity_type': 'user'}
   39 
   40         public_id = PROVIDERS.id_generator_api.generate_public_ID(local_entity)
   41 
   42         user = {
   43             'id': public_id,
   44             'domain_id': domain_id,
   45             'enabled': True
   46         }
   47         if email:
   48             user['email'] = email
   49         with sql.session_for_write() as session:
   50             federated_ref = model.FederatedUser.from_dict(federated_dict)
   51             user_ref = model.User.from_dict(user)
   52             user_ref.created_at = datetime.datetime.utcnow()
   53             user_ref.federated_users.append(federated_ref)
   54             session.add(user_ref)
   55             return identity_base.filter_user(user_ref.to_dict())
   56 
   57     @sql.handle_conflicts(conflict_type='federated_user')
   58     def create_federated_object(self, fed_dict):
   59         with sql.session_for_write() as session:
   60             fed_ref = model.FederatedUser.from_dict(fed_dict)
   61             session.add(fed_ref)
   62 
   63     def delete_federated_object(self, user_id):
   64         with sql.session_for_write() as session:
   65             q = session.query(model.FederatedUser)
   66             q = q.filter(model.FederatedUser.user_id == user_id)
   67             q.delete(False)
   68 
   69     def get_federated_objects(self, user_id):
   70         with sql.session_for_read() as session:
   71             query = session.query(model.FederatedUser)
   72             query = query.filter(model.FederatedUser.user_id == user_id)
   73             fed_ref = []
   74             for row in query:
   75                 m = model.FederatedUser(
   76                     idp_id=row.idp_id,
   77                     protocol_id=row.protocol_id,
   78                     unique_id=row.unique_id)
   79                 fed_ref.append(m.to_dict())
   80             return base.federated_objects_to_list(fed_ref)
   81 
   82     def _update_query_with_federated_statements(self, hints, query):
   83         statements = []
   84         for filter_ in hints.filters:
   85             if filter_['name'] == 'idp_id':
   86                 statements.append(
   87                     model.FederatedUser.idp_id == filter_['value'])
   88             if filter_['name'] == 'protocol_id':
   89                 statements.append(
   90                     model.FederatedUser.protocol_id == filter_['value'])
   91             if filter_['name'] == 'unique_id':
   92                 statements.append(
   93                     model.FederatedUser.unique_id == filter_['value'])
   94 
   95         # Remove federated attributes to prevent redundancies from
   96         # sql.filter_limit_query which filters remaining hints
   97         hints.filters = [
   98             x for x in hints.filters if x['name'] not in ('idp_id',
   99                                                           'protocol_id',
  100                                                           'unique_id')]
  101         query = query.filter(sqlalchemy.and_(*statements))
  102         return query
  103 
  104     def get_federated_users(self, hints):
  105         with sql.session_for_read() as session:
  106             query = session.query(model.User).outerjoin(
  107                 model.LocalUser).outerjoin(model.FederatedUser)
  108             query = query.filter(model.User.id == model.FederatedUser.user_id)
  109             query = self._update_query_with_federated_statements(hints, query)
  110             name_filter = None
  111             for filter_ in hints.filters:
  112                 if filter_['name'] == 'name':
  113                     name_filter = filter_
  114                     query = query.filter(
  115                         model.FederatedUser.display_name == name_filter[
  116                             'value'])
  117                     break
  118             if name_filter:
  119                 hints.filters.remove(name_filter)
  120             user_refs = sql.filter_limit_query(model.User, query, hints)
  121             return [identity_base.filter_user(x.to_dict()) for x in user_refs]
  122 
  123     def get_federated_user(self, idp_id, protocol_id, unique_id):
  124         # NOTE(notmorgan): Open a session here to ensure .to_dict is called
  125         # within an active session context. This will prevent lazy-load
  126         # relationship failure edge-cases
  127         # FIXME(notmorgan): Eventually this should not call `to_dict` here and
  128         # rely on something already in the session context to perform the
  129         # `to_dict` call.
  130         with sql.session_for_read():
  131             user_ref = self._get_federated_user(idp_id, protocol_id, unique_id)
  132             return identity_base.filter_user(user_ref.to_dict())
  133 
  134     def _get_federated_user(self, idp_id, protocol_id, unique_id):
  135         """Return the found user for the federated identity.
  136 
  137         :param idp_id: The identity provider ID
  138         :param protocol_id: The federation protocol ID
  139         :param unique_id: The user's unique ID (unique within the IdP)
  140         :returns User: Returns a reference to the User
  141 
  142         """
  143         with sql.session_for_read() as session:
  144             query = session.query(model.User).outerjoin(model.LocalUser)
  145             query = query.join(model.FederatedUser)
  146             query = query.filter(model.FederatedUser.idp_id == idp_id)
  147             query = query.filter(model.FederatedUser.protocol_id ==
  148                                  protocol_id)
  149             query = query.filter(model.FederatedUser.unique_id == unique_id)
  150             try:
  151                 user_ref = query.one()
  152             except sql.NotFound:
  153                 raise exception.UserNotFound(user_id=unique_id)
  154             return user_ref
  155 
  156     def set_last_active_at(self, user_id):
  157         if CONF.security_compliance.disable_user_account_days_inactive:
  158             with sql.session_for_write() as session:
  159                 user_ref = session.query(model.User).get(user_id)
  160                 user_ref.last_active_at = datetime.datetime.utcnow().date()
  161 
  162     @sql.handle_conflicts(conflict_type='federated_user')
  163     def update_federated_user_display_name(self, idp_id, protocol_id,
  164                                            unique_id, display_name):
  165         with sql.session_for_write() as session:
  166             query = session.query(model.FederatedUser)
  167             query = query.filter(model.FederatedUser.idp_id == idp_id)
  168             query = query.filter(model.FederatedUser.protocol_id ==
  169                                  protocol_id)
  170             query = query.filter(model.FederatedUser.unique_id == unique_id)
  171             query = query.filter(model.FederatedUser.display_name !=
  172                                  display_name)
  173             query.update({'display_name': display_name})
  174             return
  175 
  176     @sql.handle_conflicts(conflict_type='nonlocal_user')
  177     def create_nonlocal_user(self, user_dict):
  178         new_user_dict = copy.deepcopy(user_dict)
  179         # remove local_user attributes from new_user_dict
  180         new_user_dict.pop('name', None)
  181         new_user_dict.pop('password', None)
  182         # create nonlocal_user dict
  183         new_nonlocal_user_dict = {
  184             'name': user_dict['name']
  185         }
  186         with sql.session_for_write() as session:
  187             new_nonlocal_user_ref = model.NonLocalUser.from_dict(
  188                 new_nonlocal_user_dict)
  189             new_user_ref = model.User.from_dict(new_user_dict)
  190             new_user_ref.created_at = datetime.datetime.utcnow()
  191             new_user_ref.nonlocal_user = new_nonlocal_user_ref
  192             session.add(new_user_ref)
  193             return identity_base.filter_user(new_user_ref.to_dict())
  194 
  195     @oslo_db_api.wrap_db_retry(retry_on_deadlock=True)
  196     def delete_user(self, user_id):
  197         with sql.session_for_write() as session:
  198             ref = self._get_user(session, user_id)
  199 
  200             q = session.query(model.UserGroupMembership)
  201             q = q.filter_by(user_id=user_id)
  202             q.delete(False)
  203 
  204             session.delete(ref)
  205 
  206     def get_user(self, user_id):
  207         with sql.session_for_read() as session:
  208             user_ref = self._get_user(session, user_id)
  209             return identity_base.filter_user(user_ref.to_dict())
  210 
  211     def _get_user(self, session, user_id):
  212         user_ref = session.query(model.User).get(user_id)
  213         if not user_ref:
  214             raise exception.UserNotFound(user_id=user_id)
  215         return user_ref
  216 
  217     def list_federated_users_info(self, hints=None):
  218         with sql.session_for_read() as session:
  219             query = session.query(model.FederatedUser)
  220             fed_user_refs = sql.filter_limit_query(model.FederatedUser, query,
  221                                                    hints)
  222             return [x.to_dict() for x in fed_user_refs]
  223 
  224     def add_user_to_group_expires(self, user_id, group_id):
  225         def get_federated_user():
  226             with sql.session_for_read() as session:
  227                 query = session.query(model.FederatedUser)
  228                 query = query.filter_by(user_id=user_id)
  229                 user = query.first()
  230                 if not user:
  231                     # Note(knikolla): This shouldn't really ever happen, since
  232                     # this requires the user to already be logged in.
  233                     raise exception.UserNotFound(user_id=user_id)
  234                 return user
  235 
  236         with sql.session_for_write() as session:
  237             user = get_federated_user()
  238             query = session.query(model.ExpiringUserGroupMembership)
  239             query = query.filter_by(user_id=user_id)
  240             query = query.filter_by(group_id=group_id)
  241             membership = query.first()
  242 
  243             if membership:
  244                 membership.last_verified = datetime.datetime.utcnow()
  245             else:
  246                 session.add(model.ExpiringUserGroupMembership(
  247                     user_id=user_id,
  248                     group_id=group_id,
  249                     idp_id=user.idp_id,
  250                     last_verified=datetime.datetime.utcnow()
  251                 ))