Skip to content
Snippets Groups Projects
Commit d87376a6 authored by Martin's avatar Martin
Browse files

Import Upstream version 1.2.0

parent 91e732d0
No related branches found
No related tags found
No related merge requests found
language: python
python:
- "2.7"
- "3.4"
- "3.5"
env:
- KRB5_VER="1.10"
......@@ -11,12 +11,14 @@ env:
matrix:
exclude:
- python: "3.4"
- python: "3.5"
env: KRB5_VER="1.10"
include:
- python: "3.3"
env: KRB5_VER="1.12"
- python: "2.7"
- python: "3.4"
env: KRB5_VER="1.13"
- python: "3.5"
env: KRB5_VER="heimdal"
install: sh -ex .travis.install.sh
......@@ -34,7 +36,7 @@ deploy:
on:
repo: pythongssapi/python-gssapi
tags: true
python: "3.4"
python: "3.5"
condition: "$KRB5_VER = '1.13'"
skip_cleanup: true
- provider: pypi
......@@ -45,7 +47,7 @@ deploy:
on:
repo: pythongssapi/python-gssapi
tags: true
python: "3.4"
python: "3.5"
condition: "$KRB5_VER = '1.13'"
skip_cleanup: true
docs_dir: travis_docs_build/html
......@@ -21,6 +21,9 @@ Python-GSSAPI provides both low-level and high level wrappers around the GSSAPI
C libraries. While it focuses on the Kerberos mechanism, it should also be
useable with other GSSAPI mechanisms.
Documentation for the latest released version can be found at
`https://pythonhosted.org/gssapi <https://pythonhosted.org/gssapi>`_.
Requirements
============
......@@ -34,6 +37,8 @@ Basic
* either the `enum34` Python package or Python 3.4+
* the `six` and `decorator` python packages
Compiling from Scratch
----------------------
......@@ -59,6 +64,8 @@ Easy Way
From the Git Repo
-----------------
After being sure to install all the requirements,
.. code-block:: bash
$ git clone https://github.com/pythongssapi/python-gssapi.git
......
Sphinx >= 1.3.1
sphinx-rtd-theme >= 0.1.7
sphinx-rtd-theme >= 0.1.9
sphinxcontrib-napoleon >= 0.2.8
recommonmark >= 0.4.0
from recommonmark.parser import CommonMarkParser
from docutils import nodes
# treats "verbatim" (code without a language specified) as a code sample
class AllCodeCommonMarkParser(CommonMarkParser):
def verbatim(self, text):
node = nodes.literal_block(text, text)
self.current_node.append(node)
A Basic Introduction to GSSAPI
==============================
GSSAPI (which stands for "Generic Security Service API") is an
standard layer for interfacing with security services. While it
supports multiple different mechanisms, it is most commonly used
with Kerberos 5 ("krb5" for short).
This tutorial will provide a basic introduction to interacting with
GSSAPI through Python.
*Note*: This file is designed to be runnable using
[YALPT](https://github.com/directxman12/yalpt). You can also just
read it normally.
To start out, we'll import python-gssapi, and save the current FQDN
for later:
>>> import gssapi, socket
>>> FQDN = socket.getfqdn()
>>>
Note that this assumes you have a KRB5 realm set up, and some relevant
functions available in the `REALM` object (see gssapi-console.py, or
try `$ run-lit -e gssapi basic-tutorial.md` when you have both
gssapi-console and yalpt installed). Any actions performed using the
`REALM` object are not part of the GSSAPI library; the `REALM` object
simply contians wrappers to krb5 commands generally run separately from
the application using GSSAPI.
Names and Credentials
---------------------
Two important concepts in GSSAPI are *names* and *credentials*.
*Names*, as the name suggests, identify different entities, be they
users or services. GSSAPI has the concept of different *name types*.
These represent different types of names and corresponding sytaxes
for representing names as strings.
Suppose we wanted to refer to an HTTP server on the current host.
We could refer to it as a *host-based service*, or in the default
mechanism form (in this case, for krb5):
>>> server_hostbased_name = gssapi.Name('http@' + FQDN, name_type=gssapi.NameType.hostbased_service)
>>> server_hostbased_name
Name(b'http@sross', <OID 1.2.840.113554.1.2.1.4>)
>>> server_name = gssapi.Name('http/sross@')
>>> server_name
Name(b'http/sross@', None)
>>>
These are both effectively the same, but if we *canonicalize* both
names with respect to krb5, we'll see that GSSAPI knows they're the
same:
>>> server_name == server_hostbased_name
False
>>> server_canon_name = server_name.canonicalize(gssapi.MechType.kerberos)
>>> server_hostbased_canon_name = server_hostbased_name.canonicalize(gssapi.MechType.kerberos)
>>> server_canon_name == server_hostbased_canon_name
True
>>>
To compare two names of different name types, you should canonicalize
them first.
*Credentials* represent identification for a user or service. In
order to establish secure communication with other entities, a user
or service first needs credentials. For the krb5 mechanism,
credentials generally represent a handle to the TGT.
Credentials may be acquired for a particular name, or the default set
of credentials may be acquired.
For instance, suppose that we are writing a server, and wish to
communicate accept connections as the 'http' service. We would need
to acquire credentials as such:
>>> REALM.addprinc('http/%s@%s' % (FQDN, REALM.realm))
>>> REALM.extract_keytab('http/%s@%s' % (FQDN, REALM.realm), REALM.keytab)
>>> server_creds = gssapi.Credentials(usage='accept', name=server_name)
>>>
Note that for the krb5 mechanism, in order to acquire credentials with
the GSSAPI, the system must already have a way to access those credentials.
For users, this generally means that they have already performed a `kinit`
(i.e. have cached a TGT), while for services (like above), having a keytab
is sufficient. This process is generally performed outside the application
using the GSSAPI.
Credentials have a *usage*: 'accept' for accepting security contexts,
'initiate' for initiating security contexts, or 'both' for
credentials used for both initiating and accepting security contexts.
Credentials also have an associated *name*, *lifetime* (which may
be `None` for indefinite), and set of *mechansims* with which the
credentials are usable:
>>> server_creds.usage
'accept'
>>> server_creds.name == server_name
True
>>> server_creds.lifetime is None
True
>>> gssapi.MechType.kerberos in server_creds.mechs
True
>>> gssapi.MechType.kerberos in server_creds.mechs
True
>>>
Each of these settings is setable from the constructor as `usage`,
`name`, `lifetime`, and `mechs`.
Security Contexts
-----------------
*Security contexts* represent active sessions between two different
entities. Security contexts are used to verify identities, as well
as ensure *integrity* (message signing), *confidentiality* (message
encryption), or both for messages exchanged between the two parties.
When establishing a security context, the default credentials are
used unless otherwise specified. This allows applications to use
the user's already acquired credentials:
>>> client_ctx = gssapi.SecurityContext(name=server_name, usage='initiate')
>>> initial_client_token = client_ctx.step()
>>> client_ctx.complete
False
>>>
Just like credentials, security contexts are either initiating
contexts, or accepting contexts (they cannot be both). Initating
contexts must specify at least a target name. In this case,
we indicate that we wish to establish a context with the HTTP server
from above. The http server can then accept that context:
>>> server_ctx = gssapi.SecurityContext(creds=server_creds, usage='accept')
>>> initial_server_token = server_ctx.step(initial_client_token)
>>>
As you can see, creating an accepting security context is similar.
Here, we specify a set of accepting credentials to use, although
this is optional (the defaults will be used if no credentials are
specified).
Let's finish up the exchange:
>>> server_tok = initial_server_token
>>>
>>> while not (client_ctx.complete and server_ctx.complete):
... client_tok = client_ctx.step(server_tok)
... if not client_tok:
... break
... server_tok = server_ctx.step(client_tok)
...
>>> client_ctx.complete and server_ctx.complete
True
>>>
We can now wrap and unwrap messages, using the `wrap` and `unwrap` methods
on `SecurityContext`:
>>> message = b'some message here'
>>> wrapped_message, msg_encrypted = client_ctx.wrap(message, True)
>>> message not in wrapped_message
True
>>> msg_encrypted
True
>>> server_ctx.unwrap(wrapped_message)
UnwrapResult(message=b'some message here', encrypted=True, qop=0)
>>>
We can use the second parameter to control whether or not we encrypt the
messages, or just sign them:
>>> signed_message, msg_encrypted = client_ctx.wrap(message, False)
>>> msg_encrypted
False
>>> message in signed_message
True
>>> server_ctx.unwrap(signed_message)
UnwrapResult(message=b'some message here', encrypted=False, qop=0)
>>>
Manually passing in a second parameter and checking whether or not encryption
was used can get tedious, so python-gssapi provides two convinience methods
to help with this: `encrypt` and `decrypt`. If the context is set up to use
encryption, they will call `wrap` with encryption. If not, they will
call `wrap` without encryption.
>>> encrypted_message = client_ctx.encrypt(message)
>>> encrypted_message != message
True
>>> server_ctx.decrypt(encrypted_message)
b'some message here'
>>>
Notice that if we try to use `decrypt` a signed message, and exception will be raised,
since the context was set up to use encryption (the default):
>>> signed_message, _ = client_ctx.wrap(message, False)
>>> server_ctx.decrypt(signed_message)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 2, in decrypt
File "/home/directxman12/dev/gssapi/gssapi-console/.venv/lib/python3.4/site-packages/gssapi/_utils.py", line 167, in check_last_err
return func(self, *args, **kwargs)
File "/home/directxman12/dev/gssapi/gssapi-console/.venv/lib/python3.4/site-packages/gssapi/sec_contexts.py", line 295, in decrypt
unwrapped_message=res.message)
gssapi.exceptions.EncryptionNotUsed: Confidentiality was requested, but not used: The context was established with encryption, but unwrapped message was not encrypted.
>>>
There you have it: the basics of GSSAPI. You can use the `help` function
at the interpreter, or check the [docs](http://pythonhosted.org/gssapi/)
for more information.
......@@ -21,6 +21,8 @@ import sys, os
sys.path.insert(0, os.path.abspath('../..'))
sys.path.insert(0, os.path.abspath('../custom_extensions'))
from custom_recommonmark import AllCodeCommonMarkParser
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
......@@ -33,8 +35,13 @@ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'sphinx.ext.todo',
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# Parsers for different suffixes
source_parsers = {
'.md': AllCodeCommonMarkParser
}
# The suffix of source filenames.
source_suffix = '.rst'
source_suffix = ['.rst', '.md']
# The encoding of source files.
#source_encoding = 'utf-8-sig'
......@@ -51,9 +58,9 @@ copyright = u'2014, The Python-GSSAPI team'
# built documents.
#
# The short X.Y version.
version = '1.1.3'
version = '1.2.0'
# The full version, including alpha/beta/rc tags.
release = '1.1.3'
release = '1.2.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
......
......@@ -21,14 +21,23 @@ representing the primary abstractions that GSSAPI provides:
Main Classes
------------
Names
"""""
.. automodule:: gssapi.names
:members:
:undoc-members:
Credentials
"""""""""""
.. automodule:: gssapi.creds
:members:
:undoc-members:
Security Contexts
"""""""""""""""""
.. automodule:: gssapi.sec_contexts
:members:
:undoc-members:
......
......@@ -19,13 +19,16 @@ corresponding C functions. The high-level API makes use of the low-level API
to access underlying GSSAPI functionality. Additionally certain extensions
are currently only available from the low-level API.
Contents:
To get started, check out the :doc:`tutorials page <tutorials>` or jump
straight into the :doc:`high-level API documentation <gssapi>`.
.. toctree::
:maxdepth: 2
:hidden:
:maxdepth: 3
gssapi.rst
gssapi.raw.rst
tutorials.rst
Indices and tables
......
Tutorials
=========
To get started with using Python-GSSAPI, check out some of the following tutorials:
.. toctree::
:maxdepth: 1
basic-tutorial.md
......@@ -22,7 +22,8 @@ class SecurityContext(rsec_contexts.SecurityContext):
:class:`~gssapi.raw.sec_contexts.SecurityContext` class,
and thus may used with both low-level and high-level API methods.
This class may be pickled an unpickled.
This class may be pickled and unpickled (the attached delegated
credentials object will not be preserved, however).
"""
def __new__(cls, base=None, token=None,
......@@ -106,7 +107,7 @@ class SecurityContext(rsec_contexts.SecurityContext):
self._channel_bindings = channel_bindings
self._creds = creds
self.delegated_creds = None
self._delegated_creds = None
else:
# we already have a context in progress, just inspect it
......@@ -418,6 +419,18 @@ class SecurityContext(rsec_contexts.SecurityContext):
"""The amount of time for which this context remains valid"""
return rsec_contexts.context_time(self)
@property
def delegated_creds(self):
"""The credentials delegated from the initiator to the acceptor
.. warning::
This value will not be preserved across picklings. These should
be separately exported and transfered.
"""
return self._delegated_creds
initiator_name = _utils.inquire_property(
'initiator_name', 'The :class:`Name` of the initiator of this context')
target_name = _utils.inquire_property(
......@@ -511,7 +524,10 @@ class SecurityContext(rsec_contexts.SecurityContext):
res = rsec_contexts.accept_sec_context(token, self._creds,
self, self._channel_bindings)
self.delegated_creds = Credentials(res.delegated_creds)
if res.delegated_creds is not None:
self._delegated_creds = Credentials(res.delegated_creds)
else:
self._delegated_creds = None
self._complete = not res.more_steps
......
......@@ -206,9 +206,16 @@ long_desc = re.sub('\.\. role:: \w+\(code\)\s*\n\s*.+', '',
re.sub(r'\.\. code-block:: \w+', '::',
open('README.txt').read())))
install_requires = [
'decorator',
'six >= 1.4.0'
]
if sys.version_info < (3, 4):
install_requires.append('enum34')
setup(
name='gssapi',
version='1.1.3',
version='1.2.0',
author='The Python GSSAPI Team',
author_email='sross@redhat.com',
packages=['gssapi', 'gssapi.raw', 'gssapi.raw._enum_extensions',
......@@ -259,9 +266,5 @@ setup(
extension_file('password_add', 'gss_add_cred_with_password'),
]),
keywords=['gssapi', 'security'],
install_requires=[
'enum34',
'decorator',
'six'
]
install_requires=install_requires
)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment