def test_works(self):
        # Initial entities. Don't call 'record_revision' to imitate "old"
        # application without history related code.
        @ndb.transactional
        def make_auth_db():
            model.AuthGlobalConfig(key=model.root_key()).put()
            model.AuthIPWhitelistAssignments(
                key=model.ip_whitelist_assignments_key()).put()
            model.AuthGroup(key=model.group_key('A group')).put()
            model.AuthIPWhitelist(
                key=model.ip_whitelist_key('A whitelist')).put()
            model.replicate_auth_db()

        make_auth_db()

        # Bump auth_db once more to avoid hitting trivial case of "processing first
        # revision ever".
        auth_db_rev = ndb.transaction(model.replicate_auth_db)
        self.assertEqual(2, auth_db_rev)

        # Now do the work.
        change_log.ensure_initial_snapshot(auth_db_rev)

        # Generated new AuthDB rev with updated entities.
        self.assertEqual(3, model.get_auth_db_revision())

        # Check all *History entitites exist now.
        p = model.historical_revision_key(3)
        self.assertIsNotNone(
            ndb.Key('AuthGlobalConfigHistory', 'root', parent=p).get())
        self.assertIsNotNone(
            ndb.Key('AuthIPWhitelistAssignmentsHistory', 'default',
                    parent=p).get())
        self.assertIsNotNone(
            ndb.Key('AuthGroupHistory', 'A group', parent=p).get())
        self.assertIsNotNone(
            ndb.Key('AuthIPWhitelistHistory', 'A whitelist', parent=p).get())

        # Call again, should be noop (marker is set).
        change_log.ensure_initial_snapshot(3)
        self.assertEqual(3, model.get_auth_db_revision())
Example #2
0
  def test_works(self):
    # Initial entities. Don't call 'record_revision' to imitate "old"
    # application without history related code.
    @ndb.transactional
    def make_auth_db():
      model.AuthGlobalConfig(key=model.root_key()).put()
      model.AuthIPWhitelistAssignments(
          key=model.ip_whitelist_assignments_key()).put()
      model.AuthGroup(key=model.group_key('A group')).put()
      model.AuthIPWhitelist(key=model.ip_whitelist_key('A whitelist')).put()
      model.replicate_auth_db()
    make_auth_db()

    # Bump auth_db once more to avoid hitting trivial case of "processing first
    # revision ever".
    auth_db_rev = ndb.transaction(model.replicate_auth_db)
    self.assertEqual(2, auth_db_rev)

    # Now do the work.
    change_log.ensure_initial_snapshot(auth_db_rev)

    # Generated new AuthDB rev with updated entities.
    self.assertEqual(3, model.get_auth_db_revision())

    # Check all *History entitites exist now.
    p = model.historical_revision_key(3)
    self.assertIsNotNone(
        ndb.Key('AuthGlobalConfigHistory', 'root', parent=p).get())
    self.assertIsNotNone(
        ndb.Key(
            'AuthIPWhitelistAssignmentsHistory', 'default', parent=p).get())
    self.assertIsNotNone(ndb.Key('AuthGroupHistory', 'A group', parent=p).get())
    self.assertIsNotNone(
        ndb.Key('AuthIPWhitelistHistory', 'A whitelist', parent=p).get())

    # Call again, should be noop (marker is set).
    change_log.ensure_initial_snapshot(3)
    self.assertEqual(3, model.get_auth_db_revision())
Example #3
0
    def test_works(self):
        def perms_from_authdb():
            e = model.realms_globals_key().get()
            return [p.name for p in e.permissions] if e else []

        # The initial state.
        self.assertEqual(model.get_auth_db_revision(), 0)
        self.assertEqual(perms_from_authdb(), [])

        # Create the initial copy of AuthRealmsGlobals.
        self.call(fake_db('rev1', ['luci.dev.p1', 'luci.dev.p2']))
        self.assertEqual(model.get_auth_db_revision(), 1)
        self.assertEqual(perms_from_authdb(), ['luci.dev.p1', 'luci.dev.p2'])

        # Noop change.
        self.call(fake_db('rev1', ['luci.dev.p1', 'luci.dev.p2']))
        self.assertEqual(model.get_auth_db_revision(), 1)
        self.assertEqual(perms_from_authdb(), ['luci.dev.p1', 'luci.dev.p2'])

        # Real change.
        self.call(fake_db('rev2', ['luci.dev.p3']))
        self.assertEqual(model.get_auth_db_revision(), 2)
        self.assertEqual(perms_from_authdb(), ['luci.dev.p3'])
Example #4
0
    def test_import_external_groups(self):
        self.mock_now(datetime.datetime(2010, 1, 2, 3, 4, 5, 6))

        importer.write_config("""
      tarball {
        domain: "example.com"
        groups: "ldap/new"
        oauth_scopes: "scope"
        systems: "ldap"
        url: "https://fake_tarball"
      }
      plainlist {
        group: "external_1"
        oauth_scopes: "scope"
        url: "https://fake_external_1"
      }
      plainlist {
        domain: "example.com"
        group: "external_2"
        oauth_scopes: "scope"
        url: "https://fake_external_2"
      }
    """)

        self.mock_urlfetch({
            'https://fake_tarball':
            build_tar_gz({
                'ldap/new': 'a\nb',
            }),
            'https://fake_external_1':
            '[email protected]\[email protected]\n',
            'https://fake_external_2':
            '123\n456',
        })

        # Should be deleted during import, since not in a imported bundle.
        group('ldap/deleted', []).put()
        # Should be updated.
        group('external/external_1', ['x', 'y']).put()
        # Should be removed, since not in list of external groups.
        group('external/deleted', []).put()

        # Run the import.
        initial_auth_db_rev = model.get_auth_db_revision()
        importer.import_external_groups()
        self.assertEqual(initial_auth_db_rev + 1, model.get_auth_db_revision())

        # Verify final state.
        expected_groups = {
            'ldap/new': {
                'auth_db_rev': 1,
                'auth_db_prev_rev': None,
                'created_by': model.get_service_self_identity(),
                'created_ts': datetime.datetime(2010, 1, 2, 3, 4, 5, 6),
                'description': u'',
                'globs': [],
                'members': [ident('a'), ident('b')],
                'modified_by': model.get_service_self_identity(),
                'modified_ts': datetime.datetime(2010, 1, 2, 3, 4, 5, 6),
                'nested': [],
                'owners': u'administrators',
            },
            'external/external_1': {
                'auth_db_rev': 1,
                'auth_db_prev_rev': None,
                'created_by': ident('admin'),
                'created_ts': datetime.datetime(1999, 1, 2, 3, 4, 5, 6),
                'description': u'',
                'globs': [],
                'members': [ident('*****@*****.**'),
                            ident('*****@*****.**')],
                'modified_by': model.get_service_self_identity(),
                'modified_ts': datetime.datetime(2010, 1, 2, 3, 4, 5, 6),
                'nested': [],
                'owners': u'administrators',
            },
            'external/external_2': {
                'auth_db_rev': 1,
                'auth_db_prev_rev': None,
                'created_by': model.get_service_self_identity(),
                'created_ts': datetime.datetime(2010, 1, 2, 3, 4, 5, 6),
                'description': u'',
                'globs': [],
                'members': [ident('123'), ident('456')],
                'modified_by': model.get_service_self_identity(),
                'modified_ts': datetime.datetime(2010, 1, 2, 3, 4, 5, 6),
                'nested': [],
                'owners': u'administrators',
            },
        }
        self.assertEqual(expected_groups, fetch_groups())
Example #5
0
    def test_update_many_projects(self):
        self.assertEqual(model.get_auth_db_revision(), 0)

        cfg_rev = lambda proj, realm, rev_sfx: config.RealmsCfgRev(
            project_id=proj,
            config_rev='cfg-rev-' + rev_sfx,
            config_digest='digest-' + rev_sfx,
            config_body='realms{ name: "%s" }' % realm,
            perms_rev=None)

        # Create a bunch of project configs at once.
        config.update_realms(fake_db('db-rev1'), [
            cfg_rev('proj1', 'realm1', 'p1s1'),
            cfg_rev('proj2', 'realm1', 'p2s1'),
        ], 'New config')

        # Produced a single revision.
        self.assertEqual(model.get_auth_db_revision(), 1)

        # Present now.
        revs = config.get_stored_revs_async().get_result()
        self.assertEqual(revs, [
            config.RealmsCfgRev(
                project_id='proj1',
                config_rev=u'cfg-rev-p1s1',
                config_digest=u'digest-p1s1',
                config_body=None,
                perms_rev=u'db-rev1',
            ),
            config.RealmsCfgRev(
                project_id='proj2',
                config_rev=u'cfg-rev-p2s1',
                config_digest=u'digest-p2s1',
                config_body=None,
                perms_rev=u'db-rev1',
            ),
        ])
        self.assertEqual(
            model.project_realms_key('proj1').get().config_rev, 'cfg-rev-p1s1')
        self.assertEqual(
            model.project_realms_key('proj2').get().config_rev, 'cfg-rev-p2s1')

        # One is modified significantly, another not.
        config.update_realms(
            fake_db('db-rev1'),
            [
                cfg_rev('proj1', 'realm1', 'p1s2'),  # noop change
                cfg_rev('proj2', 'realm2', 'p2s2'),  # significant change
            ],
            'New config')

        revs = config.get_stored_revs_async().get_result()
        self.assertEqual(
            model.project_realms_key('proj1').get().config_rev, 'cfg-rev-p1s1')
        self.assertEqual(
            model.project_realms_key('proj2').get().config_rev, 'cfg-rev-p2s2')

        # One config is broken.
        config.update_realms(fake_db('db-rev1'), [
            cfg_rev('proj1', 'realm3', 'p1s3'),
            cfg_rev('proj2', '@@@@@@', 'p2s3'),
        ], 'New config')
        revs = config.get_stored_revs_async().get_result()
        self.assertEqual(
            model.project_realms_key('proj1').get().config_rev, 'cfg-rev-p1s3')
        self.assertEqual(
            model.project_realms_key('proj2').get().config_rev, 'cfg-rev-p2s2')
Example #6
0
    def test_realms_config_lifecycle(self, project_id):
        self.assertEqual(model.get_auth_db_revision(), 0)

        # A new config appears.
        rev = config.RealmsCfgRev(project_id=project_id,
                                  config_rev='cfg_rev1',
                                  config_digest='digest1',
                                  config_body='realms{ name: "realm1" }',
                                  perms_rev=None)
        config.update_realms(fake_db('db-rev1'), [rev], 'New config')

        # Generated new AuthDB revisions.
        self.assertEqual(model.get_auth_db_revision(), 1)

        # Stored now in the expanded form.
        ent = model.project_realms_key(project_id).get()
        self.assertEqual([r.name for r in ent.realms.realms],
                         ['%s:@root' % project_id,
                          '%s:realm1' % project_id])
        self.assertEqual(ent.config_rev, 'cfg_rev1')
        self.assertEqual(ent.perms_rev, 'db-rev1')

        # Permissions DB changes in a way that doesn't affect the expanded form.
        config.update_realms(fake_db('db-rev2'), [rev], 'Reeval')

        # Seeing the same AuthDB version.
        self.assertEqual(model.get_auth_db_revision(), 1)

        # The config body changes in a way that doesn't affect the expanded form.
        rev = config.RealmsCfgRev(
            project_id=project_id,
            config_rev='cfg_rev2',
            config_digest='digest2',
            config_body='realms{ name: "realm1" }  # blah blah',
            perms_rev=None)
        config.update_realms(fake_db('db-rev2'), [rev], 'Updated config')

        # Still the same AuthDB version.
        self.assertEqual(model.get_auth_db_revision(), 1)

        # The config change significantly now.
        rev = config.RealmsCfgRev(project_id=project_id,
                                  config_rev='cfg_rev3',
                                  config_digest='digest3',
                                  config_body='realms{ name: "realm2" }',
                                  perms_rev=None)
        config.update_realms(fake_db('db-rev2'), [rev], 'Updated config')

        # New revision.
        self.assertEqual(model.get_auth_db_revision(), 2)

        # And new body.
        ent = model.project_realms_key(project_id).get()
        self.assertEqual([r.name for r in ent.realms.realms],
                         ['%s:@root' % project_id,
                          '%s:realm2' % project_id])
        self.assertEqual(ent.config_rev, 'cfg_rev3')
        self.assertEqual(ent.perms_rev, 'db-rev2')

        # The config is gone.
        config.delete_realms(project_id)

        # This generated a new revision.
        self.assertEqual(model.get_auth_db_revision(), 3)

        # And it is indeed gone.
        ent = model.project_realms_key(project_id).get()
        self.assertIsNone(ent)

        # The second deletion is noop.
        config.delete_realms(project_id)
        self.assertEqual(model.get_auth_db_revision(), 3)
Example #7
0
  def test_import_external_groups(self):
    self.mock_now(datetime.datetime(2010, 1, 2, 3, 4, 5, 6))

    importer.write_config("""
      tarball {
        domain: "example.com"
        groups: "ldap/new"
        oauth_scopes: "scope"
        systems: "ldap"
        url: "https://fake_tarball"
      }
      plainlist {
        group: "external_1"
        oauth_scopes: "scope"
        url: "https://fake_external_1"
      }
      plainlist {
        domain: "example.com"
        group: "external_2"
        oauth_scopes: "scope"
        url: "https://fake_external_2"
      }
    """)

    self.mock_urlfetch({
      'https://fake_tarball': build_tar_gz({
        'ldap/new': 'a\nb',
      }),
      'https://fake_external_1': '[email protected]\[email protected]\n',
      'https://fake_external_2': '123\n456',
    })

    # Should be deleted during import, since not in a imported bundle.
    group('ldap/deleted', []).put()
    # Should be updated.
    group('external/external_1', ['x', 'y']).put()
    # Should be removed, since not in list of external groups.
    group('external/deleted', []).put()

    # Run the import.
    initial_auth_db_rev = model.get_auth_db_revision()
    importer.import_external_groups()
    self.assertEqual(initial_auth_db_rev + 1, model.get_auth_db_revision())

    # Verify final state.
    expected_groups = {
      'ldap/new': {
        'auth_db_rev': 1,
        'auth_db_prev_rev': None,
        'created_by': model.get_service_self_identity(),
        'created_ts': datetime.datetime(2010, 1, 2, 3, 4, 5, 6),
        'description': u'',
        'globs': [],
        'members': [ident('a'), ident('b')],
        'modified_by': model.get_service_self_identity(),
        'modified_ts': datetime.datetime(2010, 1, 2, 3, 4, 5, 6),
        'nested': [],
        'owners': u'administrators',
      },
      'external/external_1': {
        'auth_db_rev': 1,
        'auth_db_prev_rev': None,
        'created_by': ident('admin'),
        'created_ts': datetime.datetime(1999, 1, 2, 3, 4, 5, 6),
        'description': u'',
        'globs': [],
        'members': [ident('*****@*****.**'), ident('*****@*****.**')],
        'modified_by': model.get_service_self_identity(),
        'modified_ts': datetime.datetime(2010, 1, 2, 3, 4, 5, 6),
        'nested': [],
        'owners': u'administrators',
      },
      'external/external_2': {
        'auth_db_rev': 1,
        'auth_db_prev_rev': None,
        'created_by': model.get_service_self_identity(),
        'created_ts': datetime.datetime(2010, 1, 2, 3, 4, 5, 6),
        'description': u'',
        'globs': [],
        'members': [ident('123'), ident('456')],
        'modified_by': model.get_service_self_identity(),
        'modified_ts': datetime.datetime(2010, 1, 2, 3, 4, 5, 6),
        'nested': [],
        'owners': u'administrators',
      },
    }
    self.assertEqual(expected_groups, fetch_groups())
Example #8
0
  def test_import_external_groups(self):
    self.mock_now(datetime.datetime(2010, 1, 2, 3, 4, 5, 6))

    service_id = auth.Identity.from_bytes('service:some-service')
    self.mock(auth, 'get_service_self_identity', lambda: service_id)

    importer.write_config([
      {
        'domain': 'example.com',
        'format': 'tarball',
        'groups': ['ldap/new'],
        'oauth_scopes': ['scope'],
        'systems': ['ldap'],
        'url': 'https://fake_tarball',
      },
      {
        'format': 'plainlist',
        'group': 'external_1',
        'oauth_scopes': ['scope'],
        'url': 'https://fake_external_1',
      },
      {
        'description': 'Some external group',
        'domain': 'example.com',
        'format': 'plainlist',
        'group': 'external_2',
        'oauth_scopes': ['scope'],
        'url': 'https://fake_external_2',
      },
    ])

    self.mock_urlfetch({
      'https://fake_tarball': build_tar_gz({
        'ldap/new': 'a\nb',
      }),
      'https://fake_external_1': '[email protected]\[email protected]\n',
      'https://fake_external_2': '123\n456',
    })

    # Should be deleted during import, since not in a imported bundle.
    group('ldap/deleted', []).put()
    # Should be updated.
    group('external/external_1', ['x', 'y']).put()
    # Should be removed, since not in list of external groups.
    group('external/deleted', []).put()

    # Run the import.
    initial_auth_db_rev = model.get_auth_db_revision()
    importer.import_external_groups()
    self.assertEqual(initial_auth_db_rev + 1, model.get_auth_db_revision())

    # Verify final state.
    expected_groups = {
      'ldap/new': {
        'created_by': service_id,
        'created_ts': datetime.datetime(2010, 1, 2, 3, 4, 5, 6),
        'description': u'',
        'globs': [],
        'members': [ident('a'), ident('b')],
        'modified_by': service_id,
        'modified_ts': datetime.datetime(2010, 1, 2, 3, 4, 5, 6),
        'nested': [],
      },
      'external/external_1': {
        'created_by': ident('admin'),
        'created_ts': datetime.datetime(1999, 1, 2, 3, 4, 5, 6),
        'description': u'',
        'globs': [],
        'members': [ident('*****@*****.**'), ident('*****@*****.**')],
        'modified_by': service_id,
        'modified_ts': datetime.datetime(2010, 1, 2, 3, 4, 5, 6),
        'nested': [],
      },
      'external/external_2': {
        'created_by': service_id,
        'created_ts': datetime.datetime(2010, 1, 2, 3, 4, 5, 6),
        'description': u'',
        'globs': [],
        'members': [ident('123'), ident('456')],
        'modified_by': service_id,
        'modified_ts': datetime.datetime(2010, 1, 2, 3, 4, 5, 6),
        'nested': [],
      },
    }
    self.assertEqual(expected_groups, fetch_groups())
Example #9
0
    def test_import_external_groups(self):
        self.mock_now(datetime.datetime(2010, 1, 2, 3, 4, 5, 6))

        service_id = auth.Identity.from_bytes('service:some-service')
        self.mock(auth, 'get_service_self_identity', lambda: service_id)

        importer.write_config([
            {
                'domain': 'example.com',
                'format': 'tarball',
                'groups': ['ldap/new'],
                'oauth_scopes': ['scope'],
                'systems': ['ldap'],
                'url': 'https://fake_tarball',
            },
            {
                'format': 'plainlist',
                'group': 'external_1',
                'oauth_scopes': ['scope'],
                'url': 'https://fake_external_1',
            },
            {
                'description': 'Some external group',
                'domain': 'example.com',
                'format': 'plainlist',
                'group': 'external_2',
                'oauth_scopes': ['scope'],
                'url': 'https://fake_external_2',
            },
        ])

        self.mock_urlfetch({
            'https://fake_tarball':
            build_tar_gz({
                'ldap/new': 'a\nb',
            }),
            'https://fake_external_1':
            '[email protected]\[email protected]\n',
            'https://fake_external_2':
            '123\n456',
        })

        # Should be deleted during import, since not in a imported bundle.
        group('ldap/deleted', []).put()
        # Should be updated.
        group('external/external_1', ['x', 'y']).put()
        # Should be removed, since not in list of external groups.
        group('external/deleted', []).put()

        # Run the import.
        initial_auth_db_rev = model.get_auth_db_revision()
        importer.import_external_groups()
        self.assertEqual(initial_auth_db_rev + 1, model.get_auth_db_revision())

        # Verify final state.
        expected_groups = {
            'ldap/new': {
                'created_by': service_id,
                'created_ts': datetime.datetime(2010, 1, 2, 3, 4, 5, 6),
                'description': u'',
                'globs': [],
                'members': [ident('a'), ident('b')],
                'modified_by': service_id,
                'modified_ts': datetime.datetime(2010, 1, 2, 3, 4, 5, 6),
                'nested': [],
            },
            'external/external_1': {
                'created_by': ident('admin'),
                'created_ts': datetime.datetime(1999, 1, 2, 3, 4, 5, 6),
                'description': u'',
                'globs': [],
                'members': [ident('*****@*****.**'),
                            ident('*****@*****.**')],
                'modified_by': service_id,
                'modified_ts': datetime.datetime(2010, 1, 2, 3, 4, 5, 6),
                'nested': [],
            },
            'external/external_2': {
                'created_by': service_id,
                'created_ts': datetime.datetime(2010, 1, 2, 3, 4, 5, 6),
                'description': u'',
                'globs': [],
                'members': [ident('123'), ident('456')],
                'modified_by': service_id,
                'modified_ts': datetime.datetime(2010, 1, 2, 3, 4, 5, 6),
                'nested': [],
            },
        }
        self.assertEqual(expected_groups, fetch_groups())