Example #1
0
def sync_member_roles(cursor: Cursor, member: Member) -> ResultSet:
    """
    Adjust grants for society roles to match the given member's memberships.
    """
    user = _user_name(member)
    current = set()
    seen = set()
    for database in mysql.get_user_databases(cursor, user):
        name = _database_name_rev(database)
        # Filter active roles to those owned by society accounts.
        if name == member.crsid:
            continue
        if name not in seen:
            try:
                get_society(name)
            except KeyError:
                continue
            else:
                seen.add(name)
        if name in seen:
            current.add((user, database))
    needed = set()
    for role in mysql.get_users(cursor, *(_user_name(soc) for soc in member.societies)):
        databases = (_database_name(role), _database_name(role, "%"))
        needed.update({(user, database) for database in databases})
    return _sync_roles(cursor, current, needed)
Example #2
0
 def resolve_references(self, sess):
     super(SocietyJob, self).resolve_references(sess)
     try:
         self.society = queries.get_society(self.society_society)
     except KeyError:
         # maybe the society doesn't exist yet / any more
         self.society = None
Example #3
0
def create_society(sess: SQLASession,
                   name: str,
                   description: str,
                   admins: Set[str],
                   role_email: str = None) -> Result[Society]:
    """
    Register or update a society in the database.
    """
    try:
        soc = get_society(name, sess)
    except KeyError:
        soc = Society(society=name,
                      description=description,
                      admins=get_members(sess, *admins),
                      role_email=role_email)
        sess.add(soc)
        state = State.success
    else:
        if admins != soc.admin_crsids:
            raise ValueError("Admins for {!r} are {}, expecting {}".format(
                name, soc.admin_crsids, admins))
        soc.description = description
        soc.role_email = role_email
        state = State.success if sess.is_modified(soc) else State.unchanged
    return Result(state, soc)
Example #4
0
def sync_member_roles(cursor: Cursor, member: Member) -> ResultSet:
    """
    Adjust grants for society roles to match the given member's memberships.
    """
    username = owner_name(member)
    current = set()
    for role in pgsql.get_user_roles(cursor, username):
        # Filter active roles to those owned by society accounts.
        if role[0] == member.crsid:
            continue
        try:
            get_society(role[0])
        except KeyError:
            continue
        else:
            current.add((username, role))
    roles = pgsql.get_roles(cursor, *(soc.society for soc in member.societies))
    needed = set((username, role) for role in roles)
    return _sync_roles(cursor, current, needed)
Example #5
0
 def test_create_society(self):
     name = "test"
     description = "Test Society {}".format(self.now)
     role_email = "sysadmins-python-unittest-{}@srcf.net".format(self.now)
     soc = Society(society=name, description=description, role_email=role_email)
     sess.add(soc)
     sess.flush()
     got = queries.get_society(name, sess)
     self.assertIs(soc, got)
     self.assertIsInstance(soc.uid, int)
     self.assertIsInstance(soc.gid, int)
Example #6
0
def sync_member_roles(cursor: Cursor, member: Member) -> Collect[None]:
    """
    Adjust grants for society roles to match the given member's memberships.
    """
    if not member.societies:
        return
    username = owner_name(member)
    current: Set[Tuple[str, pgsql.Role]] = set()
    for role in pgsql.get_user_roles(cursor, username):
        # Filter active roles to those owned by society accounts.
        if role[0] == member.crsid:
            continue
        try:
            get_society(role[0])
        except KeyError:
            continue
        else:
            current.add((username, role))
    roles = pgsql.get_roles(cursor, *(soc.society for soc in member.societies))
    needed = set((username, role) for role in roles)
    yield from _sync_roles(cursor, current, needed)
Example #7
0
def destroy_test_session(sess: Session) -> None:
    """
    Remove the member and society records auto-generated in `create_test_session`, and revert the
    global session of `srcf.database.queries` to the default state.
    """
    soc = queries.get_society("unittest", sess)
    mem = queries.get_member("spqr2", sess)
    sess.begin()
    soc.admins.remove(mem)
    sess.delete(soc)
    sess.delete(mem)
    sess.commit()
    queries._global_session = None
    queries._auto_create_global_session = True
Example #8
0
def _sync_society_admins(sess: SQLASession, society: Society,
                         admins: Set[str]) -> Collect[None]:
    society = get_society(society.society, sess)
    if society.admin_crsids == admins:
        return
    group = unix.get_group(society.gid)
    for crsid in admins - society.admin_crsids:
        member = get_member(crsid, sess)
        yield bespoke.add_society_admin(sess, member, society, group)
    for crsid in society.admin_crsids - admins:
        member = get_member(crsid, sess)
        yield bespoke.remove_society_admin(sess, member, society, group)
    with mysql.context() as cursor:
        yield mysql.sync_society_roles(cursor, society)
    with pgsql.context() as cursor:
        yield pgsql.sync_society_roles(cursor, society)
Example #9
0
 def wrap(opts: Optional[DocOptArgs] = None):
     extra: Dict[str, Any] = {}
     if opts is None:
         doc = cleandoc(fn.__doc__.format(script=label))
         opts = docopt(doc)
     # Detect resolvable-typed arguments and fill in their values.
     sig = signature(fn)
     ok = True
     for param in sig.parameters.values():
         name = param.name
         cls = param.annotation
         if cls is DocOptArgs:
             extra[name] = opts
             continue
         elif cls is SQLASession:
             extra[name] = sess
             continue
         try:
             try:
                 value = cast(str, opts[name.upper()])
             except KeyError:
                 value = cast(str, opts["<{}>".format(name)])
         except KeyError:
             raise RuntimeError("Missing argument {!r}".format(name))
         try:
             if cls is Member:
                 extra[name] = get_member(value, sess)
             elif cls is Society:
                 extra[name] = get_society(value, sess)
             elif cls is Owner:
                 extra[name] = get_member_or_society(value, sess)
             else:
                 raise RuntimeError("Bad parameter {!r} type {!r}".format(
                     name, cls))
         except KeyError:
             ok = False
             error("{!r} is not valid for parameter {!r}".format(
                 value, name),
                   colour="1")
     if not ok:
         sys.exit(1)
     try:
         fn(**extra)
     except Exception:
         sess.rollback()
     else:
         sess.commit()
Example #10
0
def remove_society_admin(member: Member, society: Society) -> ResultSet:
    """
    Demote a member from a society account's list of admins.
    """
    with bespoke.context() as sess:
        member = get_member(member.crsid, sess)
        society = get_society(society.society, sess)
        results = ResultSet(bespoke.remove_from_society(sess, member, society))
    results.extend(
        unix.remove_from_group(unix.get_user(member.crsid),
                               unix.get_group(society.society)),
        bespoke.link_soc_home_dir(member, society))
    with mysql_context() as cursor:
        results.extend(mysql.sync_society_roles(cursor, member))
    with pgsql_p.context() as cursor:
        results.extend(pgsql.sync_society_roles(cursor, member))
    return results
Example #11
0
def add_society_admin(member: Member, society: Society) -> ResultSet:
    """
    Promote a member to a society account admin.
    """
    with bespoke.context() as sess:
        # Re-fetch under current session for transaction safety.
        member = get_member(member.crsid, sess)
        society = get_society(society.society, sess)
        results = ResultSet(bespoke.add_to_society(sess, member, society))
    results.extend(
        unix.add_to_group(unix.get_user(member.crsid),
                          unix.get_group(society.society)),
        bespoke.link_soc_home_dir(member, society))
    with mysql_context() as cursor:
        results.extend(mysql.sync_society_roles(cursor, member))
    with pgsql_p.context() as cursor:
        results.extend(pgsql.sync_society_roles(cursor, member))
    return results
Example #12
0
def ensure_society(sess: SQLASession,
                   name: str,
                   description: str,
                   role_email: Optional[str] = None) -> Collect[Society]:
    """
    Register or update a society in the database.

    For existing societies, this will synchronise member relations with the given list of admins.
    """
    try:
        society = get_society(name, sess)
    except KeyError:
        res_record = yield from _create_society(sess, name, description,
                                                role_email)
        society = res_record.value
    else:
        yield _update_society(sess, society, description, role_email)
    return society
Example #13
0
def create_sysadmin(member: Member) -> ResultSet:
    """
    Create an administrative account for an existing member.
    """
    if not member.user:
        raise ValueError("{!r} is not an active user")
    username = "******".format(member.crsid)
    real_name = "{} (Sysadmin Account)".format(member.name)
    results = ResultSet()
    user = results.add(unix.create_user(username, real_name=real_name)).value
    results.extend(unix.add_to_group(user, unix.get_group("sysadmins")),
                   unix.add_to_group(user, unix.get_group("adm")))
    # TODO: sed -i~ -re "/^sysadmin/ s/$/ (,$admuser,)/" /etc/netgroup
    for soc in ("executive", "srcf-admin", "srcf-web"):
        results.extend(add_society_admin(member, get_society(soc)))
    with pgsql_p.context() as cursor:
        results.extend(
            pgsql_p.create_user(cursor, username),
            pgsql_p.grant_role(cursor, username,
                               pgsql_p.get_role(cursor, "sysadmins")))
    return results
Example #14
0
def create_sysadmin(sess: SQLASession,
                    member: Member,
                    new_passwd: bool = False) -> Collect[Optional[Password]]:
    """
    Create an administrative account for an existing member.
    """
    if not member.user:
        raise ValueError("{!r} is not an active user")
    username = "******".format(member.crsid)
    real_name = "{} (Sysadmin Account)".format(member.name)
    res_group = yield from unix.ensure_group(username)
    group = res_group.value
    res_user = yield from unix.ensure_user(username,
                                           gid=group.gr_gid,
                                           real_name=real_name)
    new_user = res_user.state == State.created
    user = res_user.value
    if new_user or new_passwd:
        res_passwd = yield from unix.reset_password(user)
        passwd = res_passwd.value
    else:
        passwd = None
    if res_user or passwd:
        yield bespoke.update_nis(new_user)
    yield unix.create_home(user, os.path.join("/home", username))
    yield unix.create_home(user, os.path.join("/public/home", username), True)
    yield bespoke.populate_home_dir(member)
    yield unix.add_to_group(user, unix.get_group("sysadmins"))
    yield unix.add_to_group(user, unix.get_group("adm"))
    yield unix.grant_netgroup(user, "sysadmins")
    for soc in ("executive", "srcf-admin", "srcf-web"):
        yield add_society_admin(sess, member, get_society(soc, sess))
    with pgsql.context() as cursor:
        yield pgsql_p.ensure_user(cursor, username)
        yield pgsql_p.grant_role(cursor, username,
                                 pgsql_p.get_role(cursor, "sysadmins"))
    return passwd
Example #15
0
 def setUpClass(cls) -> None:
     cls.mem = queries.get_member("spqr2", sess)
     cls.soc = queries.get_society("unittest", sess)