Metadata-Version: 2.1
Name: scitokens
Version: 1.9.7
Summary: SciToken reference implementation library
Home-page: https://scitokens.org
Author: Brian Bockelman
Author-email: team@scitokens.org
License: Apache-2.0
Project-URL: Documentation, https://scitokens.readthedocs.io/
Project-URL: Issue Tracker, https://github.com/scitokens/scitokens/issues
Project-URL: Source Code, https://github.com/scitokens/scitokens
Description: SciTokens Library
        =================
        
        |pypi| |downloads| |license|
        
        .. |pypi| image:: https://badge.fury.io/py/scitokens.svg
           :target: https://pypi.org/project/scitokens/
        
        .. |downloads| image:: https://img.shields.io/pypi/dd/scitokens
           :target: https://pypi.org/project/scitokens
           :alt: Downloads per month
        
        .. |license| image:: https://img.shields.io/github/license/scitokens/scitokens
           :target: https://choosealicense.com/licenses/apache-2.0/
           :alt: License information
        
        This library aims to be a reference implementation of the SciTokens'
        JSON Web Token (JWT) token format.
        
        SciTokens is built on top of the
        `PyJWT <https://github.com/jpadilla/pyjwt>`__ and
        `cryptography <https://cryptography.io/en/latest/>`__ libraries. We aim
        to provide a safe, high-level interface for token manipulation, avoiding
        common pitfalls of using the underling libraries directly.
        
        *NOTE*: SciTokens (the format and this library) is currently being
        designed; this README describes how we would like it to work, not
        necessarily current functionality. The ideas behind the separate `Validator` in this
        library is taken from
        `libmacaroons <https://github.com/rescrv/libmacaroons>`__.
        
        Generating Tokens
        -----------------
        
        Usage revolves around the `SciToken` object. This can be generated
        directly:
        
        ::
        
            >>> import scitokens
            >>> token = scitokens.SciToken() # Create token and generate a new private key
            >>> token2 = scitokens.SciToken(key=private_key) # Create token using existing key
        
        where ``key`` is a private key object (more later on generating private
        keys). Direct generation using a private key will most often be done by
        token issuers.
        
        Tokens contain zero or more claims, which are facts about the token that
        typically indicate some sort of authorization the bearer of the token
        has. A token has a list of key-value pairs; each token can only have a
        single value per key.
        
        To set a claim, one can use dictionary-like setter:
        
        ::
        
            >>> token['claim1'] = 'value2'
        
        The value of each claim should be a Python object that can be serialized
        to JSON.
        
        Token Serialization
        -------------------
        
        SciTokens are built on top of JSON Web Tokens (JWT), which define a
        useful base64-encoded serialization format. A serialized token may look
        something like this:
        
        ::
        
            eyJhbGciOiJFUzI1NiIsImN3ayI6eyJ5IjoiazRlM1FFeDVjdGJsWmNrVkhINlkzSFZoTzFadUxVVWNZQW5ON0xkREV3YyIsIngiOiI4TkU2ZEE2T1g4NHBybHZEaDZUX3kwcWJOYmc5a2xWc2pYQnJnSkw5aElBIiwiY3J2IjoiUC0yNTYiLCJrdHkiOiJFQyJ9LCJ0eXAiOiJKV1QiLCJ4NXUiOiJodHRwczovL3ZvLmV4YW1wbGUuY29tL0pXUyJ9.eyJyZWFkIjoiL2xpZ28ifQ.uXVzbcOBCK4S4W89HzlWNmnE9ZcpuRHKTrTXYv8LZL9cDy3Injf97xNPm756fKcYwBO5KykYngFrUSGa4owglA.eyJjcnYiOiAiUC0yNTYiLCAia3R5IjogIkVDIiwgImQiOiAieWVUTTdsVXk5bGJEX2hnLVVjaGp0aXZFWHZxSWxoelJQVEVaZDBaNFBpOCJ9
        
        This is actually 4 separate base64-encoded strings, separated by the
        ``.`` character. The four pieces are:
        
        -  A *header*, implementing the JSON Web Key standard, specifying the
           cryptographic properties of the token.
        -  A *payload*, specifying the claims (key-value pairs) encoded by the
           token and asserted by the VO.
        -  A *signature* of the header and payload, ensuring authenticity of the
           payload.
        -  A *key*, utilized to sign any derived tokens. The key is an optional
           part of the token format, but may be required by some remote
           services.
        
        Given a serialized token, the `scitokens` library can deserialize it:
        
        ::
        
            >>> token = scitokens.SciToken.deserialize(token_serialized_bytes)
        
        As part of the deserialization, the `scitokens` library will throw an
        exception if token verification failed.
        
        The existing token can be serialized with the `SciToken.serialize` method:
        
        ::
        
            >>> token_serialized_bytes = token.serialize()
        
        Validating Tokens
        -----------------
        
        In SciTokens, we try to distinguish between *validating* and *verifying*
        tokens. Here, verification refers to determining the integrity and
        authenticity of the token: can we validate the token came from a known
        source without tampering? Validation
        is determining whether the claims of the token are satisfied in a given
        context.
        
        For example, if a token contains the claims
        ``{vo: ligo, op: read, path: /ligo}``, we would first verify that the
        token is correctly signed by a known public key associated with LIGO.
        When presented to a storage system along with an HTTP request, the
        storage system would validate the token authorizes the corresponding
        request (is it a GET request? Is it for a sub-path of /ligo?).
        
        Within the `scitokens` module, validation is done by the `Validator`
        object:
        
        ::
        
            >>> val = scitokens.Validator()
        
        This object can be reused for multiple validations. All SciToken claims
        must be validated. There are no "optional" claim attributes or values.
        
        To validate a specific claim, provide a callback function to the
        `Validator` object:
        
        ::
        
            >>> def validate_op(value):
            ...     return value == True
            >>> val.add_validator("op", validate_op)
        
        Once all the known validator callbacks have been registered, use the
        `~Validator.validate` method with a token:
        
        ::
        
            >>> val.validate(token)
        
        This will throw a `ValidationException` if the token could not be
        validated.
        
        Enforcing SciTokens Logic
        -------------------------
        For most users of SciTokens, determining that a token is valid is insufficient.
        Rather, most will be asking "does this token allow the current resource
        request?"  The valid token must be compared to some action the user is
        attempting to take.
        
        To assist in the authorization enforcement, the SciTokens library provides
        the `Enforcer` class.
        
        An unique Enforcer object is needed for each thread:
        
        ::
        
            >>> enf = scitokens.Enforcer("https://scitokens.org/dteam")
        
        The ``Enforcer`` class accepts a single issuer string, or a sequence of
        issuer strings, for which tokens are required to match one element.
        
        This object will accept tokens targeted to any audience; a more typical
        use case will look like the following:
        
        ::
        
            >>> enf = scitokens.Enforcer("https://scitokens.org/dteam",
                                         audience="https://example.com")
        
        This second enforcer would not accept tokens that are intended for
        https://google.com.
        
        The enforcer can then test authorization logic against a valid token:
        
        ::
        
            >>> token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtp..."
            >>> stoken = scitokens.SciToken.deserialize(token)
            >>> enf.generate_acls(stoken)
            [(u'write', u'/store/user/bbockelm'), (u'read', u'/store')]
            >>> enf.test(stoken, "read", "/store/foo")
            True
            >>> enf.test(stoken, "write", "/store/foo")
            False
            >>> enf.test(stoken, "write", "/store/user/foo")
            False
            >>> enf.test(stoken, "write", "/store/user/bbockelm/foo")
            True
        
        The `Enforcer.test` method uses the SciTokens built-in path parsing to validate the
        authorization.  The `Enforcer.generate_acls` method allows the caller to cache
        the ACL information from the token.
        
        Creating Sample Tokens
        ----------------------
        
        Typically, an access token is generated during an OAuth2 workflow to facilitate 
        authentication and authorization. However, for testing and experimentation purposes, 
        `the demo token generator <https://demo.scitokens.org/>`__ provides users with the
        ability to create sample tokens with customized payload:
        
        ::
            
            >>> payload = {"sub": "<email adress>", "scope": "read:/protected"}
            >>> token = scitokens.utils.demo.token(payload)
        
        The `~scitokens.utils.demo.token` method makes a request to the generator to create a serialized token 
        for the specified payload. Users can also retrieve a parsed token by calling the 
        `~scitokens.utils.demo.parsed_token` method, which returns a SciToken object corresponding to the 
        token. The object contains the decoded token data, including the claims and signature. 
        
        Decorator
        -------------
        
        The ``protect`` decorator is designed to be used with a `flask <https://flask.palletsprojects.com/>`_ application. It can be used like:
        
        .. code-block:: python
        
            @scitokens_protect.protect(audience="https://demo.scitokens.org", scope="read:/secret", issuer="https://demo.scitokens.org")
            def Secret(token: SciToken):
                # ... token is now available.
        
        The possible arguments are:
        
        - ``audience`` (str or list): Audience expected in the client token
        - ``scope`` (str): Scope required to access the function
        - ``issuer`` (str): The issuer to require of the client token
        
        The protected function can optionally take an argument ``token``, which is the parsed SciToken object.
        
        Configuration
        -------------
        
        An optional configuration file can be provided that will alter the behavior of 
        the SciTokens library.  Configuration options include:
        
        ================== ========================================================================================
        Key                Description
        ================== ========================================================================================
        log_level          The log level for which to use.  Options include: CRITICAL, ERROR, WARNING, INFO, DEBUG.
                           Default: WARNING
        log_file           The full path to the file to log.
                           Default: None
        cache_lifetime     The minimum lifetime (in seconds) of keys in the keycache.
                           Default: 3600 seconds
        cache_location     The directory to store the KeyCache, used to store public keys across executions.
                           Default: $HOME/.cache/scitokens
        ================== ========================================================================================
        
        The configuration file is in the ini format, and will look similar to:
        
        ::
        
            [scitokens]
            log_level = DEBUG
            cache_lifetime = 60
        
        You may set the configuration by passing a file name to `set_config` function:
        
        ::
            
            >> import scitokens
            >> scitokens.set_config("/etc/scitokens/scitokens.ini")
            
        
        
        Project Status
        ==============
        
        |build| |coverage| |quality| |docs|
        
        .. |build| image:: https://img.shields.io/github/workflow/status/scitokens/scitokens/Python%20package
           :target: https://github.com/scitokens/scitokens/actions/workflows/python-package.yml
           :alt: Build pipeline status
        
        .. |coverage| image:: https://app.codacy.com/project/badge/Coverage/753108a9f8ab450d8f5598e1b639ecfd    
            :target: https://www.codacy.com/gh/scitokens/scitokens/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=scitokens/scitokens&amp;utm_campaign=Badge_Coverage
            :alt: Code coverage
        
        .. |quality| image:: https://app.codacy.com/project/badge/Grade/753108a9f8ab450d8f5598e1b639ecfd    
            :target: https://www.codacy.com/gh/scitokens/scitokens/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=scitokens/scitokens&amp;utm_campaign=Badge_Grade
            :alt: Code Quality
        
        .. |docs| image:: https://readthedocs.org/projects/scitokens/badge/?version=latest
            :target: https://scitokens.readthedocs.io/en/latest/?badge=latest
            :alt: Documentation Status
        
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.5
Description-Content-Type: text/x-rst
Provides-Extra: docs
