Hi!

>> > > Which steps, and in which order, do we have to follow?
>> > 
>> > You'd need to apply fireroles to roles.
>> [...]
>> 
>> Oh, great, it works!  Thanks so much. ;-)
> 
> Well, not really.  After applying it to our production site, only
> superadmin users could access those records and collections.
> 
> You wrote that «First thing is to create the groups and add people to
> them», 

Your initial description was refering to groups, I think.
They are not roles. A role can be applied to a group,
however.

> but, in fact, we don't have groups, we have roles.

Then the fire role does not work as it refers to groups. If
you use the roles only you'd need to hook up the users to
the role. In our setup, however, it's much easier to handle
if we add users to groups and have roles that apply to
those groups. (Mainly, casue we get a lot of external groups
via LDAP auth, and because we don't want to redo all the
user handling LDAP does already.)

> After browsing all related pages, in our 1.1.2 system and
> in github 1.1 branch, we don't see any group related
> management, except for a lonely «list groups» page that
> seems obsolete, a leftover from older versions of Invenio.

Not really. /yourgroups/ allows you to create groups. Actually, every user can 
add groups. Be careful in case you add restrictions based on groups that those 
groups are owned by admin. If you use external groups create local groups of 
the same name as otherwise people could highjack them.


> So, we did create a new role with the list of «allow groups X», «allow
> groups Y», etc, that you wrote in your mail.  We added the
> viewrestrcol with our collections.  The result was that all those
> collections were restricted for everybody except for superadmin.  We
> tried to simplify our definitions to a single role, but we didn't
> succeed.

If you have no group an no one in the group, this has to be that way, right?

> We also tried to change «allow groups X» for «allow roles X».  Again,
> no luck.  Only superadmin can access those restricted collections.
> 
> Again, are we dealing with roles or groups?  Can we manage groups, in
> Invenio 1.1.2?

You can have groups in invenio 1.1 (we use them extensively)
 
Here is a snippet of code we use to add groups to Admin

----------------------------------------------------------------------
def RegisterWorkflowGroups(GroupDict):
    """
    Register groups for workflow. All these groups belong to "admin" (uid=1).
    They need to exist and they need to belong to admin to avoid privilege
    escalation. Note that we use fireroles in our workflow based on those
    groups.

    Note that we use FIXED names:
    - EDITORS     : all editors at the institute level. They approve files from
                    user sumissions to the VDBINPRINT collection
    - STAFF       : editors at the library that approve EDITOR approvals to the
                    final VDB collection
    - STAFFNOMAIL : Users with STAFF rights but no baskets, alerts and change
                    request notifications

    Additionally, we create workflow baskets and alerts for groups of
    institutes. The group ID for those things is the same as for STAFF.
    This is used at RWTH for their workflow.

    @type Groups: dictionary
    @param Groups: Dictionary of lists containing groupname as key and
                   description as value.

    """
    logger.info('Registring groups for workflow')

    adminuid = 1      # owner of all groups
    policy   = 'VM'   # Join policy requires approval by admin
    rootGroups = groupdb.get_groups(adminuid)
    GID = {}
    # Extact GIDs for groups matching our names
    for row in rootGroups:
        for groupname in GroupDict:
            if row[1] == groupname:
                GID[groupname] = row[0]

    for name in GID:
        if name in GID:
            logger.info("Group %s already belonged to admin." % name)
        else:
            grp = groupdb.get_group_id(name)
            if grp != ():
                logger.error("Some user tried to Hijack our Workflow Groups %s"
                             % name)
                groupdb.delete_group_and_members(grp)

    for groupname in GroupDict:
        if (not groupname in GID) or (GID[groupname] == 0):
            logger.info("Inserting group %s:" % groupname)
            GID[groupname] = groupdb.insert_new_group(adminuid, groupname,
                                             GroupDict[groupname], policy)

    # Make sure admin is always admin of these groups
    for groupname in GID:
        groupdb.delete_member(GID[groupname], adminuid)
        groupdb.insert_new_member(adminuid, GID[groupname], 'A')
    return GID


def AddUser2Group(gid, uid, mail, inst, role):
    """
    Add users to the proper group GID. Additionally, add the user to local
    mimic-groups called "inst [loginmethod]", which prevents other users to
    create such a group locally and thus get privileges on restricted
    collections. In case the mimic groups don't exist, create them as well.

    @param gid: groupid
    @param uid: userid
    @param role: name for display
    @param inst: institues id
    """

    # Do not process ADMIN here as otherwise she will loose the group and
    # just become a member!
    if uid > 1:
        logger.info("Adding user to %s group:" % role)
        logger.info(" %s: %s (%s)" % (inst, mail, uid))
        groupdb.delete_member(gid, uid)
        groupdb.insert_new_member(uid, gid,
                CFG_WEBSESSION_USERGROUP_STATUS["MEMBER"])
        logger.info("   Adding to local groups...")
        for method in CFG_EXTERNAL_AUTHENTICATION.keys():
            if method == 'Local':
                # We do nothing for Local logins, we just want to add
                # our editors/staff to all external mimic groups to ensure she
                # gets proper rights in case she belongs to more than one
                # institue.
                pass
            else:
                localgrp = inst + ' ' + '[' + method + ']'
                try:
                    localGID = groupdb.get_group_id(localgrp)[0][0]
                except:
                    logger.info("   Local group ", localgrp, \
                          " did not exist. Adding...")
                    localGID = groupdb.insert_new_group(1, localgrp,
                                                        inst, 'VM')
                logger.info("      %s = %s" % (localgrp, localGID))
                groupdb.delete_member(localGID, uid)
                groupdb.insert_new_member(uid, localGID,
                        CFG_WEBSESSION_USERGROUP_STATUS["MEMBER"])
    return
----------------------------------------------------------------------

Note: role here does not refer to invenios role management
but the role people have in our workflow like Users,
Editors, Staff. In the end, those guys are connected to
roles like hgf_user, hgf_editor, hgf_staff. Sorry for this
naming clash.

For collection cration we use something similar that then
also registers roles that have the view_restr_col
permissions on the collection in question. Unfortunatly, the
code that does this is a bit heavy and recursive :S as it
hooks up with our institute authorities to keep track of
proper subordination and rights. Bascially, the whole tree
of restricted collections you can see here

https://bib-pubdb1.desy.de/collection/InstColl?ln=en

is restricted based on group membership.

I'll try to extract the essentials to give you an idea

----------------------------------------------------------------------
    rolename = 'I-' + colIntName
    roledesc = 'Institute user for ' + colIntName + '(' + colShortName +')'
    if instID is None:
        instID = ''
    firerule = ''
    for method in CFG_EXTERNAL_AUTHENTICATION.keys():
        if method == 'Local':
            # We do nothing for Local this key is not usefull
            pass
        elif method == 'Robot':
            # We do nothing for Robots.
            pass
        elif method == 'ZRobot':
            # We do nothing for ZRobots.
            pass
        else:
            # Setup roles
            grouppostfix = '[' + method + ']' # Needed for fireroles
            grpname = instID + ' ' + grouppostfix
            firerule += "allow groups '" + grpname + "'" + '\n'
    firerule += "allow groups 'STAFF'\n"
    firerule += "allow groups 'STAFFNOMAIL'\n"
    res = acc_delete_role(None, rolename)
    info("      %s roles deleted.", str(res))
    if colQuery:
        # This collection does not have children, since we have a query
        # associated
        info("""    Adding role:
          %s
          %s
          %s""", rolename,roledesc,firerule)
        res = acc_add_role(rolename, roledesc,
                 firerole_def_ser=serialize(compile_role_definition(firerule)),
                 firerole_def_src=firerule)
        if res == 0:
            info("       %s already exists.", rolename)
        else:
            info("       %s created", rolename)
        acc_add_role_action_arguments_names(rolename,
            'viewrestrcoll', collection=colIntName)
----------------------------------------------------------------------

And later on for the group generation:

----------------------------------------------------------------------
    for method in CFG_EXTERNAL_AUTHENTICATION.keys():
        if not robot, zrobot, local:
                groupowneruid_groups = groupdb.get_groups_by_user_status(1, 'A')
                # group name is [$i][1]
                isowner = False
                if groupdb.group_name_exist(grpname):
                    # check if the group is owned by groupowneruid, if not, drop
                    # it else keep it and do nothing
                    for g in groupowneruid_groups:
                        if g[1] == grpname:
                            isowner = True
                    if isowner:
                        debug("[OK ] Group ", grpname,
                              " exists and is owned by uid", groupowneruid)
                    else:
                        error("[ERR] Group ", grpname,
                              " exists, BUT HAS WRONG OWNERSHIP! Deleting...")
                        grpid = groupdb.get_group_id(grpname)[0][0]
                        groupdb.delete_group_and_members(grpid)
                        info( "      Adding the group for uid ", groupowneruid)
                        groupdb.insert_new_group(groupowneruid, grpname,
                                               colShortName, grouppolicy)
                else:
                    # A new group is born.
                    info( "Adding group ", grpname)
                    groupdb.insert_new_group(groupowneruid, grpname, 
colShortName,
                                             grouppolicy)
----------------------------------------------------------------------

HTH :)

-- 
Kind regards,

Alexander Wagner

Deutsches Elektronen-Synchrotron DESY
Library and Documentation

Building 01d Room OG1.444
Notkestr. 85
22607 Hamburg

phone:  +49-40-8998-1758
fax:    +49-40-8994-1758
e-mail: [email protected]

Reply via email to