magpie.register =============== .. py:module:: magpie.register Attributes ---------- .. autoapisummary:: magpie.register.GroupResourcePermissionsAPI magpie.register.GroupsAPI magpie.register.ServiceAPI magpie.register.ServiceResourcesAPI magpie.register.ServicesAPI magpie.register.SigninAPI magpie.register.SignoutAPI magpie.register.UserResourcePermissionsAPI magpie.register.UsersAPI magpie.register.SERVICE_TYPE_DICT magpie.register.LOGGER magpie.register.LOGIN_ATTEMPT magpie.register.LOGIN_TIMEOUT magpie.register.CREATE_SERVICE_INTERVAL magpie.register.GETCAPABILITIES_INTERVAL magpie.register.GETCAPABILITIES_ATTEMPTS magpie.register.SERVICES_MAGPIE magpie.register.SERVICES_PHOENIX magpie.register.SERVICES_PHOENIX_ALLOWED magpie.register.CONFIG_KNOWN_EXTENSIONS Exceptions ---------- .. autoapisummary:: magpie.register.RegistrationError magpie.register.RegistrationValueError magpie.register.RegistrationLoginError magpie.register.RegistrationConfigurationError Classes ------- .. autoapisummary:: magpie.register.Permission magpie.register.PermissionSet magpie.register.ServiceWPS Functions --------- .. autoapisummary:: magpie.register.validate_services_config magpie.register.get_constant magpie.register.bool2str magpie.register.get_admin_cookies magpie.register.get_json magpie.register.get_logger magpie.register.get_magpie_url magpie.register.get_phoenix_url magpie.register.get_twitcher_protected_service_url magpie.register.islambda magpie.register.print_log magpie.register.raise_log magpie.register._login_loop magpie.register._request_curl magpie.register._phoenix_update_services magpie.register._phoenix_login magpie.register._phoenix_login_check magpie.register._phoenix_remove_services magpie.register._phoenix_register_services magpie.register._register_services magpie.register.sync_services_phoenix magpie.register._magpie_add_register_services_perms magpie.register._magpie_update_services_conflict magpie.register._magpie_register_services_with_requests magpie.register._magpie_register_services_with_db_session magpie.register._load_config magpie.register.get_all_configs magpie.register._expand_all magpie.register.magpie_register_services_from_config magpie.register._handle_permission magpie.register._use_request magpie.register._parse_resource_path magpie.register._apply_permission_entry magpie.register.magpie_register_permissions_from_config magpie.register._resolve_config_registry magpie.register._process_permissions magpie.register.pseudo_random_string Module Contents --------------- .. py:data:: GroupResourcePermissionsAPI .. py:data:: GroupsAPI .. py:data:: ServiceAPI .. py:data:: ServiceResourcesAPI .. py:data:: ServicesAPI .. py:data:: SigninAPI .. py:data:: SignoutAPI .. py:data:: UserResourcePermissionsAPI .. py:data:: UsersAPI .. py:function:: validate_services_config(services_configuration: magpie.typedefs.JSON) -> magpie.typedefs.ServicesConfig Validate configuration within the ``providers`` section. .. seealso:: :ref:`config_providers` and :ref:`config_file`. :param services_configuration: Service definitions loaded from one or more combined configuration files. :return: Services configuration with validated schema and applied defaults. .. py:function:: get_constant(constant_name: magpie.typedefs.Str, settings_container: Optional[magpie.typedefs.AnySettingsContainer] = None, settings_name: Optional[magpie.typedefs.Str] = None, default_value: Optional[magpie.typedefs.SettingValue] = None, raise_not_set: bool = True, raise_missing: bool = True, print_missing: bool = False, empty_missing: bool = False) -> magpie.typedefs.SettingValue Search in order for matched value of :paramref:`constant_name`: 1. search in :py:data:`MAGPIE_CONSTANTS` 2. search in settings if specified 3. search alternative setting names (see below) 4. search in :mod:`magpie.constants` definitions 5. search in environment variables Parameter :paramref:`constant_name` is expected to have the format ``MAGPIE_[VARIABLE_NAME]`` although any value can be passed to retrieve generic settings from all above-mentioned search locations. If :paramref:`settings_name` is provided as alternative name, it is used as is to search for results if :paramref:`constant_name` was not found. Otherwise, ``magpie.[variable_name]`` is used for additional search when the format ``MAGPIE_[VARIABLE_NAME]`` was used for :paramref:`constant_name` (i.e.: ``MAGPIE_ADMIN_USER`` will also search for ``magpie.admin_user`` and so on for corresponding constants). :param constant_name: key to search for a value :param settings_container: WSGI application settings container (if not provided, uses found one in current thread) :param settings_name: alternative name for `settings` if specified :param default_value: default value to be returned if not found anywhere, and exception raises are disabled. :param raise_not_set: raise an exception if the found key is ``None``, search until last case if others are ``None`` :param raise_missing: raise exception if key is not found anywhere :param print_missing: print message if key is not found anywhere, return ``None`` :param empty_missing: consider an empty value for an existing key as if it was missing (i.e.: as if not set). :returns: found value or `default_value` :raises ValueError: if resulting value is invalid based on options (by default raise missing/empty/``None`` value) :raises LookupError: if no appropriate value could be found from all search locations (according to options) .. py:class:: Permission Bases: :py:obj:`magpie.utils.ExtendedEnum` Applicable :term:`Permission` values (names) under certain :term:`Service` and :term:`Resource`. .. py:attribute:: READ :value: 'read' .. py:attribute:: WRITE :value: 'write' .. py:attribute:: ACCESS :value: 'access' .. py:attribute:: BROWSE :value: 'browse' .. py:attribute:: GET_CAPABILITIES :value: 'getcapabilities' .. py:attribute:: GET_MAP :value: 'getmap' .. py:attribute:: GET_FEATURE_INFO :value: 'getfeatureinfo' .. py:attribute:: GET_LEGEND_GRAPHIC :value: 'getlegendgraphic' .. py:attribute:: GET_METADATA :value: 'getmetadata' .. py:attribute:: GET_PROPERTY_VALUE :value: 'getpropertyvalue' .. py:attribute:: GET_FEATURE :value: 'getfeature' .. py:attribute:: GET_FEATURE_WITH_LOCK :value: 'getfeaturewithlock' .. py:attribute:: GET_GML_OBJECT :value: 'getgmlobject' .. py:attribute:: DESCRIBE_FEATURE_TYPE :value: 'describefeaturetype' .. py:attribute:: DESCRIBE_LAYER :value: 'describelayer' .. py:attribute:: DESCRIBE_PROCESS :value: 'describeprocess' .. py:attribute:: EXECUTE :value: 'execute' .. py:attribute:: LOCK_FEATURE :value: 'lockfeature' .. py:attribute:: TRANSACTION :value: 'transaction' .. py:attribute:: CREATE_STORED_QUERY :value: 'createstoredquery' .. py:attribute:: DROP_STORED_QUERY :value: 'dropstoredquery' .. py:attribute:: LIST_STORED_QUERIES :value: 'liststoredqueries' .. py:attribute:: DESCRIBE_STORED_QUERIES :value: 'describestoredqueries' .. py:class:: PermissionSet(permission: magpie.typedefs.AnyPermissionType, access: Optional[Union[Access, magpie.typedefs.Str]] = None, scope: Optional[Union[Scope, magpie.typedefs.Str]] = None, typ: Optional[PermissionType] = None, reason: Optional[magpie.typedefs.Str] = None) Bases: :py:obj:`object` Explicit definition of a :class:`Permission` with applicable :class:`Access` and :class:`Scope` to resolve it. The :class:`Permission` is the *name* of the applicable permission on the :class:`magpie.models.Resource`. The :class:`Scope` defines how the :class:`Permission` should impact the resolution of the perceived :term:`Effective Permissions ` over a :class:`magpie.models.Resource` tree hierarchy. The :class:`Access` defines how the :class:`Permission` access should be interpreted (granted or denied). Optionally, a :class:`PermissionType` can be provided to specifically indicate which kind of permission this set represents. This type is only for informative purposes, and is not saved to database nor displayed by the explicit string representation. It is returned within JSON representation and can be employed by :term:`Effective Permissions ` resolution to be more verbose about returned results. On missing :class:`Access` or :class:`Scope` specifications, they default to :attr:`Access.ALLOW` and :attr:`Scope.RECURSIVE` to handle backward compatible naming convention of plain ``permission_name``. Initializes the permission definition, possibly using required conversion from other implementations. :param permission: Name of the permission, or any other implementation from which the name can be inferred. :param access: Effective behaviour of the permissions. Generally, grant or deny the specified permission. :param scope: Scope for which the permission affects hierarchical resources. Important for effective resolution. :param typ: Type of permission being represented. Informative only, does not impact behavior if omitted. :param reason: Slightly more indicative information on why the current permission-type has this value. Value should be either explicitly provided or will be inferred if converted from input PermissionTuple. .. seealso:: :meth:`PermissionSet._convert` .. py:attribute:: __slots__ :value: ['_name', '_access', '_scope', '_tuple', '_type', '_reason'] .. py:method:: __eq__(other: Any) -> bool Return self==value. .. py:method:: __ne__(other: Any) -> bool Return self!=value. .. py:method:: __lt__(other: Any) -> bool Ascending sort of permission according to their name, access and scope modifiers. First sort by permission name alphabetically, followed by increasing *restrictive access* and increasing *range of scoped resources*. Using this sorting methodology, similar permissions by name are grouped together first, and permissions of same name with modifiers are then ordered, the first having less priority when selecting a single item to display with conflicting possibilities. Respecting :attr:`Access.DENY` is more important than :attr:`Access.ALLOW` (to protect the :term:`Resource`), and :attr:`Scope.MATCH` is *closer* to the actual :term:`Resource` than :attr:`Scope.RECURSIVE` permission received from a *farther* parent in the hierarchy. Sorted explicit string representation becomes:: [name1]-[allow]-[match] [name1]-[allow]-[recursive] [name1]-[deny]-[match] [name1]-[deny]-[recursive] [name2]-[allow]-[match] [name2]-[allow]-[recursive] [name2]-[deny]-[match] [name2]-[deny]-[recursive] ... We then obtain two **crucial** ordering results: 1. We can easily pick the last sorted item with highest resolution priority to find the final result of corresponding permissions. (note: final result for same user or group, their direct/inherited resolution is not considered here). 2. Picking the first element with lowest priority also displays the permission that impacts the widest range of resources. For instance in Magpie UI, indicating that a permission as :attr:`Scope.RECURSIVE` is more verbose as it tell other resources under it are also receive the specified :class:`Access` modifier rather than only the punctual resource. .. warning:: Alphabetically sorting permissions by string representation (implicit/explicit) is not equivalent to sorting them according to :term:`Permission` priority according to how modifiers are resolved. To obtain the prioritized sorting as strings, a list of :class:`PermissionSet` (with the strings as input) should be used to convert and correctly interpreted the raw strings, and then be converted back after sorting. .. code-block:: python # valid priority-sorted strings [str(perm) for perm in sorted(PermissionSet(p) for p in permission_strings)] # not equivalent to raw sorting list(sorted(permission_strings)) .. py:method:: __hash__() -> int Return hash(self). .. py:method:: __str__() -> magpie.typedefs.Str Obtains the compound literal representation of the :class:`PermissionSet`. Employed for database storage supporting ``ziggurat`` format. .. py:method:: __repr__() -> magpie.typedefs.Str Obtains the visual representation of the :class:`PermissionSet`. .. py:method:: like(other: Any) -> bool Evaluates if one permission is *similar* to another permission definition regardless of *modifiers*. This is different than ``==`` operator which will evaluate *exactly* equal permission definitions. .. py:method:: json() -> magpie.typedefs.PermissionDict Obtains the JSON representation of this :class:`PermissionSet`. .. py:method:: webhook_params() -> magpie.typedefs.JSON Obtain JSON representation employed for :term:`Webhook` reference. .. py:method:: ace(user_or_group: Optional[Union[magpie.models.User, magpie.models.Group]]) -> magpie.typedefs.AccessControlEntryType Converts the :class:`PermissionSet` into an :term:`ACE` that :mod:`pyramid` can understand. .. py:property:: reason :type: Optional[magpie.typedefs.Str] Indicative reason of the returned value defined by :meth:`type` or inferred by the :class:`PermissionTuple`. .. seealso:: :meth:`combine` :returns: Single string that describes the reason (source) of the permission, or multiple strings if updated by combination of multiple permissions. .. py:method:: resolve(permission1: magpie.typedefs.ResolvablePermissionType, permission2: magpie.typedefs.ResolvablePermissionType, context: PermissionType = PermissionType.INHERITED, multiple_choice: Optional[magpie.typedefs.Str] = None) -> magpie.typedefs.ResolvablePermissionType :classmethod: Resolves provided permissions into a single one considering various modifiers and groups for a resource. Permissions **MUST** have the same :term:`Permission` name. The associated :term:`Resource` on which the two compared permissions are applied on should also be the same This method **SHOULD NOT** be used by itself to obtain for :term:`Effective Permission` since it does not handle multi-level :term:`Resource` resolution. Resolution is accomplished in this case only for a given level in the tree hierarchy. The comparison considers both the :class:`Access` and :class:`Scope` of every :term:`Inherited Permission` of the :term:`User`, as well as its :term:`Group` memberships sorted by their priority. .. seealso:: - :meth:`magpie.services.ServiceInterface.effective_permissions` - :func:`magpie.api.management.user.user_utils.combine_user_group_permissions` - :meth:`PermissionSet.__lt__` :param permission1: Permission to compare. :param permission2: Permission to compare. :param context: Control the resolution context (local/effective) of the permissions (safeguard against invalid definitions). :param multiple_choice: Alternate explanation to default :data:`PERMISSION_REASON_MULTIPLE` applied if multiple :term:`Permission` refer to distinct :term:`Group` of equal priority and equivalent access definitions, meaning they are interchangeable without impacting resolution to access the same target :term:`Resource`. :returns: Permission with highest priority to resolve access a resource without considering scope. .. py:property:: group_priority :type: Optional[magpie.typedefs.GroupPriority] Priority accessor in case of group inherited permission resolved by :class:`PermissionTuple`. .. py:property:: perm_tuple :type: Optional[ziggurat_foundations.permissions.PermissionTuple] Get the original :class:`PermissionTuple` if available (:class:`PermissionSet` must have been created by one). .. py:property:: implicit_permission :type: Optional[magpie.typedefs.Str] Obtain the implicit string representation of the :class:`PermissionSet` as plain :class:`Permission` name. This representation is backward compatible with prior versions of `Magpie` where explicit representation of permission names in the database did not exist. If the contained modifiers of the :class:`PermissionSet` (notably the :attr:`Access.DENY`) result in a string representation that is *not possible* according to non existing permissions for older `Magpie` instances, the returned value will be ``None``. .. seealso:: - :meth:`explicit_permission` for the new representation. .. py:property:: explicit_permission :type: magpie.typedefs.Str Obtain the explicit string representation of the :class:`PermissionSet`. This format is always guaranteed to be completely defined contrary to :meth:`implicit_permission`. .. seealso:: - :meth:`__str__` (default string value). - :meth:`implicit_permission` for the old representation. .. py:property:: name :type: Permission .. py:attribute:: permission .. py:property:: access :type: Access .. py:property:: scope :type: Scope .. py:property:: type :type: Optional[PermissionType] .. py:method:: _convert(permission: magpie.typedefs.AnyPermissionType) -> Optional[PermissionSet] :classmethod: Converts any permission representation to the :class:`PermissionSet` with applicable enum members. Supports older :class:`Permission` representation such that implicit conversion of permission name without :attr:`access` and :attr:`scope` values are padded with defaults. Also, pre-defined partial or full definition from literal string representation are parsed to generate the :class:`PermissionSet` instance. :param permission: implicit or explicit permission name string, or any other known permission implementation :raises ValueError: when the permission name cannot be identified or parsed .. py:data:: SERVICE_TYPE_DICT .. py:class:: ServiceWPS(service: magpie.models.Service, request: pyramid.request.Request) Bases: :py:obj:`ServiceOWS` Service that represents a ``Web Processing Service`` endpoint. Initialize the service. :param service: Base service resource that must be handled by this service implementation. :param request: Active request to handle requested resources, permissions and effective access. The request can be omitted if basic service definition details are to be retrieved. It is mandatory for any ``requested`` or ``effective`` component that should be resolved. .. py:attribute:: service_type :value: 'wps' .. py:attribute:: permissions .. py:attribute:: params_expected :value: ['service', 'request', 'version', 'identifier'] .. py:attribute:: resource_types_permissions .. py:method:: resource_requested() -> Optional[Tuple[magpie.typedefs.ServiceOrResourceType, bool]] Defines how to interpret the incoming request into the targeted :class:`model.Resource` for the given service. Each service must implement its own definition. The expected return value must be either of the following:: - List<(target-resource, target?)> When multiple resources need validation ('target?' as below for each). - (target-resource, True) when the exact resource is found according to request parsing. - (parent-resource, False) when any parent of the resource is found according to request parsing. - None when invalid request or not found resource. The ``parent-resource`` should indicate the *closest* higher-level resource in the hierarchy that would nest the otherwise desired ``target-resource``. The idea behind this is that `Magpie` will be able to resolve the effective recursive scoped permission even if not all corresponding resources were explicitly defined in the database. For example, if the request *would* be interpreted with the following hierarchy after service-specific resolution:: ServiceA Resource1 <== closest *existing* parent resource [Resource2] <== target (according to service/request resolution), but not existing in database A permission defined as Allow/Recursive on ``Resource1`` should *normally* allow access to ``Resource2``. If ``Resource2`` is not present in the database though, it cannot be looked for, and the corresponding ACL cannot be generated. Because the (real) protected service using `Magpie` can have a large and dynamic hierarchy, it is not convenient to enforce perpetual sync between it and its resource representation in `Magpie`. Using ``(parent-resource, False)`` will allow resolution of permission from the closest available parent. .. note:: In case of ``parent-resource`` returned, only `recursive`-scoped permissions will be considered, since the missing ``target-resource`` is the only one that should be checked for `match`-scoped permissions. For this reason, the service-specific implementation should preferably return the explicit `target` resource whenever possible. If the returned resource is ``None``, the ACL will effectively be resolved to denied access. This can be used to indicate failure to retrieve the expected resource or that corresponding resource does not exist. Otherwise, this method implementation should convert any request path, query parameters, etc. into an existing resource. If a list of ``(target-resource, target?)`` is returned, all of those resources should individually perform :term:`Effective Resolution` and should **ALL** simultaneously be granted access to let the request through. This can be used to resolve ambiguous or equivalent parameter combinations from parsing the request, or to validate access to parameters that allow multi-resource references using some kind of list value representation. .. seealso:: - :meth:`_get_acl` for :term:`Effective Resolution` of over multiple :term:`Resource` references. - :meth:`effective_permissions` for :term:`Effective Resolution` of a single :term:`Resource`. :returns: One or many tuple of reference resource (target/parent), and explicit match status of the corresponding resource (True/False) .. py:function:: bool2str(value: Any) -> magpie.typedefs.Str Converts :paramref:`value` to explicit ``"true"`` or ``"false"`` :class:`str` with permissive variants comparison that can represent common falsy or truthy values. .. py:function:: get_admin_cookies(container: magpie.typedefs.AnySettingsContainer, verify: bool = True, raise_message: Optional[magpie.typedefs.Str] = None) -> magpie.typedefs.CookiesType .. py:function:: get_json(request_or_response: Union[magpie.typedefs.AnyRequestType, magpie.typedefs.AnyResponseType]) -> magpie.typedefs.JSON Retrieves the 'JSON' body of a response using the property/callable according to the response's implementation. .. py:function:: get_logger(name: magpie.typedefs.Str, level: Optional[int] = None, force_stdout: bool = None, message_format: Optional[magpie.typedefs.Str] = None, datetime_format: Optional[magpie.typedefs.Str] = None) -> logging.Logger Immediately sets the logger level to avoid duplicate log outputs from the `root logger` and `this logger` when `level` is ``logging.NOTSET``. .. py:function:: get_magpie_url(container: Optional[magpie.typedefs.AnySettingsContainer] = None) -> magpie.typedefs.Str Obtains the configured Magpie URL entrypoint based on the various combinations of supported configuration settings. .. seealso:: Documentation section :ref:`config_app_settings` for available setting combinations. :param container: container that provides access to application settings. :return: resolved Magpie URL .. py:function:: get_phoenix_url(container: Optional[magpie.typedefs.AnySettingsContainer] = None) -> magpie.typedefs.Str Obtains the configured Phoenix URL entrypoint based on the various combinations of supported configuration settings. .. seealso:: Documentation section :ref:`config_phoenix` for available setting combinations. :param container: container that provides access to application settings. :return: resolved Phoenix URL .. py:function:: get_twitcher_protected_service_url(magpie_service_name: magpie.typedefs.Str, container: Optional[magpie.typedefs.AnySettingsContainer] = None, hostname: Optional[magpie.typedefs.Str] = None) -> magpie.typedefs.Str Obtains the protected service URL behind Twitcher Proxy based on combination of supported configuration settings. .. seealso:: Documentation section :ref:`config_twitcher` for available setting combinations. :param magpie_service_name: name of the service to employ in order to form the URL path behind the proxy. :param container: container that provides access to application settings. :param hostname: override literal hostname to generate the URL instead of resolving using settings. :return: resolved Twitcher Proxy protected service URL .. py:function:: islambda(func: Any) -> bool Evaluate if argument is a callable :class:`lambda` expression. .. py:function:: print_log(msg: magpie.typedefs.Str, logger: Optional[logging.Logger] = None, level: int = logging.INFO, **kwargs: Any) -> None Logs the requested message to the logger and optionally enforce printing to the console according to configuration value defined by ``MAGPIE_LOG_PRINT``. .. py:function:: raise_log(msg: magpie.typedefs.Str, exception: Type[Exception] = Exception, logger: Optional[logging.Logger] = None, level: int = logging.ERROR) -> NoReturn Logs the provided message to the logger and raises the corresponding exception afterwards. :raises exception: whichever exception provided is raised systematically after logging. .. py:data:: LOGGER .. py:data:: LOGIN_ATTEMPT :value: 5 .. py:data:: LOGIN_TIMEOUT :value: 2 .. py:data:: CREATE_SERVICE_INTERVAL :value: 2 .. py:data:: GETCAPABILITIES_INTERVAL :value: 10 .. py:data:: GETCAPABILITIES_ATTEMPTS :value: 12 .. py:data:: SERVICES_MAGPIE :value: 'MAGPIE' .. py:data:: SERVICES_PHOENIX :value: 'PHOENIX' .. py:data:: SERVICES_PHOENIX_ALLOWED .. py:exception:: RegistrationError Bases: :py:obj:`RuntimeError` Generic error during registration operation. Initialize self. See help(type(self)) for accurate signature. .. py:exception:: RegistrationValueError Bases: :py:obj:`RegistrationError`, :py:obj:`ValueError` Registration error caused by an invalid value precondition. Initialize self. See help(type(self)) for accurate signature. .. py:exception:: RegistrationLoginError Bases: :py:obj:`RegistrationError` Registration error caused by a failure to complete required login operation. Initialize self. See help(type(self)) for accurate signature. .. py:exception:: RegistrationConfigurationError Bases: :py:obj:`RegistrationValueError` Registration error caused by an invalid configuration entry or definition. Initialize self. See help(type(self)) for accurate signature. .. py:function:: _login_loop(login_url, cookies_file, data=None, message='Login response') .. py:function:: _request_curl(url: magpie.typedefs.Str, cookie_jar: Optional[magpie.typedefs.Str] = None, cookies: Optional[magpie.typedefs.Str] = None, form_params: Optional[magpie.typedefs.Str] = None, msg: Optional[magpie.typedefs.Str] = 'Response') -> Tuple[int, int] Executes a request using cURL. :returns: tuple of the returned system command code and the response http code .. py:function:: _phoenix_update_services(services_dict: magpie.typedefs.JSON) -> bool .. py:function:: _phoenix_login(cookies_file: magpie.typedefs.Str) -> bool Performs Phoenix login using provided cookies. .. py:function:: _phoenix_login_check(cookies: magpie.typedefs.Str) -> bool Since Phoenix always return 200, even on invalid login, 'hack' check unauthorized access. :param cookies: temporary cookies file storage used for login with :func:`_phoenix_login`. :return: status indicating if login access was granted with defined credentials. .. py:function:: _phoenix_remove_services() -> bool Removes the Phoenix services using temporary cookies retrieved from login with defined `PHOENIX` constants. :returns: success status of the procedure. .. py:function:: _phoenix_register_services(services_dict: Dict[magpie.typedefs.Str, Dict[magpie.typedefs.Str, Any]], allowed_service_types: Optional[List[magpie.typedefs.Str]] = None) -> Tuple[bool, Dict[magpie.typedefs.Str, int]] .. py:function:: _register_services(where: Optional[magpie.typedefs.Str], services_dict: Dict[magpie.typedefs.Str, Dict[magpie.typedefs.Str, magpie.typedefs.Str]], cookies: magpie.typedefs.Str, message: Optional[magpie.typedefs.Str] = 'Register response') -> Tuple[bool, Dict[magpie.typedefs.Str, int]] Registers services on desired location using provided configurations and access cookies. :returns: tuple of overall success and individual http response of each service registration. .. py:function:: sync_services_phoenix(services: Union[Iterable[magpie.models.Service], magpie.typedefs.JSON], services_as_dicts: bool = False) -> bool Syncs Magpie services by pushing updates to Phoenix. Services must be one of types specified in :py:data:`magpie.register.SERVICES_PHOENIX_ALLOWED`. :param services: An iterable of :class:`models.Service` by default, or a dictionary of ``{svc-name: {}}`` JSON objects containing each service's information if :paramref:`services_ad_dicts` is ``True``. where ```` is defined as:: {"public_url": , "service_name": , "service_type": } :param services_as_dicts: indicate if services must be parsed as JSON definitions. .. py:function:: _magpie_add_register_services_perms(services: magpie.typedefs.ServicesSettings, statuses: Dict[magpie.typedefs.Str, int], curl_cookies: str, request_cookies: magpie.typedefs.AnyCookiesType, disable_getcapabilities: bool) -> None .. py:function:: _magpie_update_services_conflict(conflict_services: List[magpie.typedefs.Str], services_dict: magpie.typedefs.ServicesSettings, request_cookies: magpie.typedefs.AnyCookiesType) -> Dict[magpie.typedefs.Str, int] Resolve conflicting services by name during registration by updating them only if pointing to different URL. .. py:function:: _magpie_register_services_with_requests(services_dict: magpie.typedefs.ServicesSettings, push_to_phoenix: bool, username: magpie.typedefs.Str, password: magpie.typedefs.Str, provider: magpie.typedefs.Str, force_update: bool = False, disable_getcapabilities: bool = False) -> bool Registers :term:`Services` of loaded ``providers`` configuration using API requests. .. seealso:: :func:`magpie_register_services_from_config` :param services_dict: services configuration definition. :param push_to_phoenix: push registered Magpie services to Phoenix for synced configurations. :param username: login username to use to obtain permissions for services registration. :param password: login password to use to obtain permissions for services registration. :param provider: login provider to use to obtain permissions for services registration. :param force_update: override existing services matched by name :param disable_getcapabilities: do not execute 'GetCapabilities' validation for applicable services. :return: successful operation status .. py:function:: _magpie_register_services_with_db_session(services_dict: magpie.typedefs.ServicesSettings, db_session: sqlalchemy.orm.session.Session, push_to_phoenix: bool = False, force_update: bool = False, update_getcapabilities_permissions: bool = False) -> bool Registration procedure of :term:`Services` from ``providers`` section using pre-established database session. .. seealso:: :func:`magpie_register_services_from_config` .. py:function:: _load_config(path_or_dict: Union[magpie.typedefs.Str, magpie.typedefs.CombinedConfig], section: magpie.typedefs.Str, allow_missing: bool = False) -> Union Loads a YAML/JSON file path or pre-loaded dictionary configuration. .. py:data:: CONFIG_KNOWN_EXTENSIONS .. py:function:: get_all_configs(path_or_dict: Union[magpie.typedefs.Str, magpie.typedefs.CombinedConfig], section: magpie.typedefs.Literal[groups], allow_missing: bool = False) -> magpie.typedefs.GroupsConfig get_all_configs(path_or_dict: Union[magpie.typedefs.Str, magpie.typedefs.CombinedConfig], section: magpie.typedefs.Literal[users], allow_missing: bool = False) -> magpie.typedefs.UsersConfig get_all_configs(path_or_dict: Union[magpie.typedefs.Str, magpie.typedefs.CombinedConfig], section: magpie.typedefs.Literal[permissions], allow_missing: bool = False) -> magpie.typedefs.PermissionsConfig get_all_configs(path_or_dict: Union[magpie.typedefs.Str, magpie.typedefs.CombinedConfig], section: magpie.typedefs.Literal[services], allow_missing: bool = False) -> magpie.typedefs.ServicesConfig get_all_configs(path_or_dict: Union[magpie.typedefs.Str, magpie.typedefs.CombinedConfig], section: magpie.typedefs.Literal[webhooks], allow_missing: bool = False) -> magpie.typedefs.WebhooksConfig Loads all matched configurations. Configurations are considered a valid match if they have one of the :py:data:`CONFIG_KNOWN_EXTENSIONS` (if path) and that loaded (or passed) configurations contain the specified :paramref:`section` name. If the input is a directory path, loads any number of files contained in it that fulfill matching conditions. If it is a path pointing to a single valid configuration file, loads it by itself. If a dictionary is passed, returns it directly if it fulfills validation. :param path_or_dict: directory path, file path or literal dictionary. :param section: section name that must be inside every matched configuration file to be loaded. :param allow_missing: allow to have no valid configuration after all are resolved, otherwise raises. :raises RegistrationError: when no valid configuration can be found and empty one is not allowed. :returns: - list of configurations loaded if input was a directory path - list of single configuration if input was a file path - list of single configuration if input was a JSON dict - empty list if none of the other cases where matched .. note:: Order of file loading will be resolved by alphabetically sorted filename if specifying a directory path. .. py:function:: _expand_all(config: magpie.typedefs.JSON) -> magpie.typedefs.JSON Applies environment variable expansion recursively to all applicable fields of a configuration definition. .. py:function:: magpie_register_services_from_config(service_config_path: magpie.typedefs.Str, push_to_phoenix: bool = False, skip_registration: bool = False, force_update: bool = False, disable_getcapabilities: bool = False, db_session: Optional[sqlalchemy.orm.session.Session] = None) -> magpie.typedefs.ServicesSettings Registers Magpie services from one or many `providers.cfg` file. Uses the provided DB session to directly update service definitions, or uses API request routes as admin. Optionally pushes updates to Phoenix. :param service_config_path: where to look for `providers` configuration(s). Directory or file path. :param push_to_phoenix: whether to push loaded service definitions to remote `Phoenix` service. :param skip_registration: Load, validate and combine :term:`Service` configurations, but don't register them. :param force_update: override service definitions that conflict by name with registered ones. :param disable_getcapabilities: Skip `GetCapabilities` request validation and permission update. By default, any service with `type` that allows `GetCapabilities` permissions will be tested to ensure it can be reached on the provided `url`. Once validated, this permission is applied to `anonymous` group to make its entrypoint accessible by anyone. Services that cannot have `GetCapabilities` permission are ignored regardless. :param db_session: Use a pre-established database connection for registration. Otherwise, API requests are employed. :returns: loaded service configurations. .. py:function:: _handle_permission(message: magpie.typedefs.Str, permission_index: int, trail: magpie.typedefs.Str = ', skipping...', detail: Optional[magpie.typedefs.Str] = None, permission: Optional[magpie.typedefs.Str] = None, level: Union[magpie.typedefs.Str, int] = logging.WARN, raise_errors: bool = False) -> None Logs a message related to a 'permission' entry and raises an error if required. Log message format is as follows (detail portion omitted if none provided):: {message} [permission: #{permission_index}] [{permission}]{trail} Detail: [{detail}] Such that the following logging entry is generated (omitting any additional logging formatters):: >> log_permission("test", 1, " skip test...", "just a test", "fake") test [permission: #1] [fake] skip test... Detail: [just a test] :param message: base message to log :param permission_index: index of the permission in the configuration list for traceability :param trail: trailing message appended after the base message :param detail: additional details appended after the trailing message after moving to another line. :param permission: permission name to log just before the trailing message. :param level: logging level (default: ``logging.WARN``) :param raise_errors: raises errors related to permissions, instead of just logging the info. .. seealso:: `magpie/config/permissions.cfg` .. py:function:: _use_request(cookies_or_session) .. py:function:: _parse_resource_path(permission_config_entry: magpie.typedefs.PermissionConfigItem, entry_index: int, service_info: magpie.typedefs.JSON, cookies_or_session: magpie.typedefs.CookiesOrSessionType = None, magpie_url: Optional[magpie.typedefs.Str] = None, raise_errors: bool = False) -> Tuple[Optional[int], bool] Parses the `resource` field of a permission config entry and retrieves the final resource id. Creates missing resources as necessary if they can be automatically resolved. If `cookies` are provided, uses requests to a running `Magpie` instance (with ``magpie_url``) to apply permission. If `session` to db is provided, uses direct db connection instead to apply permission. :returns: tuple of found id (if any, ``None`` otherwise), and success status of the parsing operation (error) .. py:function:: _apply_permission_entry(permission_config_entry: magpie.typedefs.PermissionConfigItem, entry_index: int, resource_id: int, cookies_or_session: magpie.typedefs.CookiesOrSessionType, magpie_url: magpie.typedefs.Str, users: magpie.typedefs.UsersSettings, groups: magpie.typedefs.GroupsSettings, raise_errors: bool = False) -> None Applies the single permission entry retrieved from the permission configuration. Assumes that permissions fields where pre-validated. Permission is applied for the user/group/resource using request or db session accordingly to arguments. .. py:function:: magpie_register_permissions_from_config(permissions_config: Union[magpie.typedefs.Str, magpie.typedefs.PermissionsConfig], settings: Optional[magpie.typedefs.AnySettingsContainer] = None, db_session: Optional[sqlalchemy.orm.session.Session] = None, raise_errors: bool = False) -> None Applies `permissions` specified in configuration(s) defined as file, directory with files or literal configuration. :param permissions_config: file/dir path to `permissions` config or JSON/YAML equivalent pre-loaded. :param settings: Magpie settings to resolve an instance session when using requests instead of DB session. Will look for ``magpie.url``, ``magpie.admin_user`` and ``magpie.admin_password`` by default, or any corresponding environment variable resolution if omitted in the settings. :param db_session: db session to use instead of requests to directly create/remove permissions with config. :param raise_errors: raises errors related to permissions, instead of just logging the info. .. seealso:: `magpie/config/permissions.cfg` for specific parameters and operational details. .. py:function:: _resolve_config_registry(config_files: Optional[magpie.typedefs.MultiConfigs], key: magpie.typedefs.Str) -> magpie.typedefs.AnyResolvedSettings Converts a list of configurations entries from multiple files into a single resolved mapping. Resolution is accomplished against :paramref:`key` to generate the mapping of unique items. First configuration entries have priority over later ones if keys are duplicated. .. py:function:: _process_permissions(permissions: magpie.typedefs.PermissionsConfig, magpie_url: magpie.typedefs.Str, cookies_or_session: sqlalchemy.orm.session.Session, users: Optional[magpie.typedefs.UsersSettings] = None, groups: Optional[magpie.typedefs.GroupsSettings] = None, settings: Optional[magpie.typedefs.AnySettingsContainer] = None, raise_errors: bool = False) -> None Processes a single `permissions` configuration. .. py:function:: pseudo_random_string(length: int = 8, allow_chars: magpie.typedefs.Str = string.ascii_letters + string.digits) -> magpie.typedefs.Str Generate a string made of random characters.