Source code for jwql.utils.permissions

#! /usr/bin/env python
"""Permissions module for managing file permissions for ``jwql``.

This module provides ``jwql`` with functions to inspect and set file
permissions.

The module takes as input a path to a file or directory, checks whether
the owner of the file is the ``jwql`` admin account, and if so, (1) set
the permissions appropriately, and (2) set the group membership
appropriately.

Authors
-------

    - Johannes Sahlmann

Use
---

    This module can be imported and used with

    ::

        from jwql.permissions import permissions
        permissions.set_permissions(pathname)

    Required arguments:

    ``pathname`` - Directory or file for which the default permissions
    should be set

Notes
-----

    Permissions are set and read using the stat module, see
    https://docs.python.org/3/library/stat.html

    Below is a list with the relevant stat attribute names, integer,
    octal, and string representations.

    ::

        stat_key stat_mode stat_mode_octal stat_mode_string
        -------- --------- --------------- ----------------
        S_IFPORT         0             0o0       ?---------
        S_IFDOOR         0             0o0       ?---------
         S_IXOTH         1             0o1       ?--------x
         S_IWOTH         2             0o2       ?-------w-
         S_IROTH         4             0o4       ?------r--
         S_IRWXO         7             0o7       ?------rwx
         S_IXGRP         8            0o10       ?-----x---
         S_IWGRP        16            0o20       ?----w----
         S_IRGRP        32            0o40       ?---r-----
         S_IRWXG        56            0o70       ?---rwx---
         S_IEXEC        64           0o100       ?--x------
         S_IXUSR        64           0o100       ?--x------
         S_IWUSR       128           0o200       ?-w-------
        S_IWRITE       128           0o200       ?-w-------
         S_IREAD       256           0o400       ?r--------
         S_IRUSR       256           0o400       ?r--------
         S_IRWXU       448           0o700       ?rwx------
         S_ISVTX       512          0o1000       ?--------T
         S_ISGID      1024          0o2000       ?-----S---
         S_ISUID      2048          0o4000       ?--S------
         S_IFIFO      4096             0o0       p---------
         S_IFCHR      8192             0o0       c---------
         S_IFDIR     16384             0o0       d---------
         S_IFBLK     24576             0o0       b---------
         S_IFREG     32768             0o0       ----------
         S_IFLNK     40960             0o0       l---------
        S_IFSOCK     49152             0o0       s---------
         S_IFWHT     57344             0o0       w---------
"""

import grp
import os
import pwd
import stat

# owner and group names for JWQL project
DEFAULT_OWNER = 'jwqladm'
DEFAULT_GROUP = 'jwql_dev'

# set the default mode for DEFAULT_OWNER
DEFAULT_MODE = stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP  # equivalent to '?rwxr-x---'


[docs]def get_group_string(pathname): """Return the group of ``pathname`` in string representation. Parameters ---------- pathname : str Directory or file to be inspected. Returns ------- group_name : str String representation of the group. """ file_statinfo = os.stat(pathname) groupinfo = grp.getgrgid(file_statinfo.st_gid) group_name = groupinfo.gr_name return group_name
[docs]def get_owner_string(pathname): """Return the owner of ``pathname`` in string representation. Parameters ---------- pathname : str Directory or file to be inspected Returns ------- owner_name : str String representation of the owner. """ file_statinfo = os.stat(pathname) ownerinfo = pwd.getpwuid(file_statinfo.st_uid) owner_name = ownerinfo.pw_name return owner_name
[docs]def has_permissions(pathname, owner=DEFAULT_OWNER, mode=DEFAULT_MODE, group=DEFAULT_GROUP): """Return boolean indicating whether ``pathname`` has the specified owner, permission, and group scheme. Parameters ---------- pathname : str Directory or file to be inspected owner : str String representation of the owner mode : int Integer representation of the permission mode, compatible with ``os.stat`` output group : str String representation of the group Returns ------- boolean : bool """ verify_path(pathname) file_statinfo = os.stat(pathname) groupinfo = grp.getgrgid(file_statinfo.st_gid) # complement mode depending on whether input is file or directory if os.path.isfile(pathname): mode = mode | stat.S_IFREG elif os.path.isdir(pathname): mode = mode | stat.S_IFDIR if (get_owner_string(pathname) != owner) or (file_statinfo.st_mode != mode)\ or (groupinfo.gr_name != group): return False return True
[docs]def set_permissions(pathname, owner=DEFAULT_OWNER, mode=DEFAULT_MODE, group=DEFAULT_GROUP, verbose=False): """Set mode and group of the file/directory identfied by ``pathname``, if and only if it is owned by ``owner``. Parameters ---------- pathname : str Directory or file to be inspected owner : str String representation of the owner mode : int Integer representation of the permission mode, compatible with ``os.stat`` output group : str String representation of the group verbose : bool Boolean indicating whether verbose output is requested """ if verbose: print('\nBefore:') show_permissions(pathname) if not has_permissions(pathname): if get_owner_string(pathname) == owner: os.chmod(pathname, mode) # change group but not owner os.chown(pathname, -1, grp.getgrnam(group).gr_gid) if verbose: print('After:') show_permissions(pathname)
[docs]def show_permissions(pathname): """Verbose output showing group, user, and permission information for a directory or file. Parameters ---------- pathname : str Directory or file to be inspected """ verify_path(pathname) file_statinfo = os.stat(pathname) ownerinfo = pwd.getpwuid(file_statinfo.st_uid) groupinfo = grp.getgrgid(file_statinfo.st_gid) if os.path.isdir(pathname): info_string = 'directory' elif os.path.isfile(pathname): info_string = 'file' print('Inspecting {}: {}'.format(info_string, pathname)) print('group {} = {}'.format(file_statinfo.st_gid, groupinfo.gr_name)) print('owner {} = {}'.format(file_statinfo.st_uid, ownerinfo.pw_name)) print('mode {} = {}'.format(file_statinfo.st_mode, stat.filemode(file_statinfo.st_mode))) print('')
[docs]def verify_path(pathname): """Verify that pathname is either a directory or a file. If not, an error is raised. Parameters ---------- pathname : str Directory or file to be inspected """ if (not os.path.isdir(pathname)) and (not os.path.isfile(pathname)): raise NotImplementedError('{} is not a valid path or filename'.format(pathname))