Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement UsernamePassword method #9

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ local/

.vscode/
.venv/
build/
19 changes: 17 additions & 2 deletions cepces/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,5 +118,20 @@ def handle(self):
class CertificateAuthenticationHandler(AuthenticationHandler):
"""Handler for Certificate based authentication."""
def handle(self):
"""Constructs and returns a SOAPAuth authentication handler."""
raise NotImplementedError()
parser = self._parser

# Ensure there's a certificate section present.
if 'certificate' not in parser:
raise RuntimeError(
'Missing "certificate" section in configuration.',
)

section = parser['certificate']

certfile = section.get('certfile', None)
keyfile = section.get('keyfile', None)

return SOAPAuth.TransportCertificateAuthentication(
certfile,
keyfile,
)
2 changes: 1 addition & 1 deletion cepces/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class Configuration(Base):
'Anonymous': SOAPAuth.AnonymousAuthentication,
'Kerberos': SOAPAuth.TransportKerberosAuthentication,
'UsernamePassword': SOAPAuth.MessageUsernamePasswordAuthentication,
'Certificate': SOAPAuth.MessageCertificateAuthentication,
'Certificate': SOAPAuth.TransportCertificateAuthentication,
}

def __init__(self, endpoint, endpoint_type, cas, auth, poll_interval):
Expand Down
1 change: 1 addition & 0 deletions cepces/soap/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

NS_SOAP = 'http://www.w3.org/2003/05/soap-envelope'
NS_ADDRESSING = 'http://www.w3.org/2005/08/addressing'
NS_WSSE = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'

# ACTION_FAULT = 'http://www.w3.org/2005/08/addressing/fault'
QNAME_FAULT = QName('http://www.w3.org/2003/05/soap-envelope', 'Fault')
41 changes: 36 additions & 5 deletions cepces/soap/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from cepces.krb5 import types as ktypes
from cepces.krb5.core import Context, Keytab, Principal
from cepces.krb5.core import CredentialOptions, Credentials, CredentialCache
from cepces.soap.types import Security as WSSecurity, UsernameToken


class Authentication(Base, metaclass=ABCMeta):
Expand All @@ -35,6 +36,11 @@ def transport(self):
"""Property containing authentication mechanism for the transport layer
(i.e. requests)."""

@abstractproperty
def clientcertificate(self):
"""Property containing TLS client certificate ínformation for the transport layer
(i.e. requests)."""

@abstractmethod
def post_process(self, envelope):
"""Method for securing (post processing) a SOAP envelope."""
Expand Down Expand Up @@ -119,6 +125,10 @@ def _init_transport(self):
def transport(self):
return self._transport

@property
def clientcertificate(self):
return None

def post_process(self, envelope):
# Nothing to be done here.
return envelope
Expand All @@ -135,15 +145,36 @@ def __init__(self, username, password):
def transport(self):
return None

@property
def clientcertificate(self):
return None

def post_process(self, envelope):
raise NotImplementedError()
envelope.header.element.append(WSSecurity.create())

envelope.header.security.element.append(UsernameToken.create())
envelope.header.security.usernametoken.username = self._username
envelope.header.security.usernametoken.password = self._password

return envelope


class TransportCertificateAuthentication(Authentication):
"""Transport authentication using a client certificate."""
def __init__(self, certfile, keyfile):
super().__init__()
self._certfile = certfile
self._keyfile = keyfile
os.system('echo DEBUG Certificate file: ""%s"" Key file ""%s"" >> /var/log/cepces/cepces.log' % ( certfile, keyfile ))
dmulder marked this conversation as resolved.
Show resolved Hide resolved

class MessageCertificateAuthentication(Authentication):
"""Message authentication using a client certificate."""
@property
def transport(self):
raise NotImplementedError()
return None

@property
def clientcertificate(self):
return ( self._certfile, self._keyfile )

def post_process(self, envelope):
raise NotImplementedError()
# Nothing to be done here.
return envelope
3 changes: 3 additions & 0 deletions cepces/soap/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,15 @@ def send(self, message):
# Post process the envelope.
if self._auth:
message = self._auth.post_process(message)
data = ElementTree.tostring(message.element)
self._logger.debug(" -data after post-processing: %s", data)

# Post the envelope and raise an error if necessary.
req = requests.post(url=self._endpoint,
data=data,
headers=headers,
verify=self._capath,
cert=self._auth.clientcertificate,
auth=self._auth.transport)

# If we get an internal server error (code 500), there's a chance that
Expand Down
43 changes: 42 additions & 1 deletion cepces/soap/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
# pylint: disable=invalid-name
"""This module contains common SOAP types."""
from xml.etree.ElementTree import Element, QName
from cepces.soap import NS_ADDRESSING, NS_SOAP
from cepces.soap import NS_ADDRESSING, NS_SOAP, NS_WSSE
from cepces.xml import NS_XSI
from cepces.xml.binding import XMLElement, XMLNode, XMLValue
from cepces.xml.converter import StringConverter
Expand Down Expand Up @@ -100,6 +100,43 @@ def create():
return element


class UsernameToken(XMLNode):
"""WSSE UsernameToken."""
username = XMLValue('Username',
converter=StringConverter,
namespace=NS_WSSE)
password = XMLValue('Password',
converter=StringConverter,
namespace=NS_WSSE)

@staticmethod
def create():
usernametoken = Element(QName(NS_WSSE, 'UsernameToken'))

username = Element(QName(NS_WSSE, 'Username'))
usernametoken.append(username)

password = Element(QName(NS_WSSE, 'Password'))
password.attrib[QName(NS_WSSE, 'Type' )] = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText'
usernametoken.append(password)

return usernametoken


class Security(XMLNode):
"""WSSE Security."""
usernametoken = XMLElement('UsernameToken',
binder=UsernameToken,
namespace=NS_WSSE)

@staticmethod
def create():
security = Element(QName(NS_WSSE, 'Security'))
security.attrib[QName(NS_SOAP, 'mustUnderstand')] = '1'

return security


class Header(XMLNode):
"""SOAP Header."""
action = XMLValue('Action',
Expand All @@ -122,6 +159,10 @@ class Header(XMLNode):
namespace=NS_ADDRESSING,
nillable=True)

security = XMLElement ('Security',
binder=Security,
namespace=NS_WSSE)

@staticmethod
def create():
header = Element(QName(NS_SOAP, 'Header'))
Expand Down
30 changes: 28 additions & 2 deletions conf/cepces.conf.dist
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ type=Policy
# Message level authentication. The credentials are used in the
# message header for authentication.
# * Certificate
# Message level authentication. A client certificate is used to
# sign the message. This is not yet implemented.
# Transport level authentication. A client certificate is used
# for TLS client authentication in the HTTPS layer.
#
# Default: Kerberos
auth=Kerberos
Expand Down Expand Up @@ -85,3 +85,29 @@ enctypes=
arcfour-hmac
aes128-cts-hmac-sha1-96
aes256-cts-hmac-sha1-96

[certificate]
# Use the following client certificate,
# given as OpenSSL format certificate file.
# The issuer CA certificate of this client certificate must be included
# in the AD NTAuth container.
#
# Default: <not defined>
#certfile = /path/to/openssl-certfile.pem

# Use the following client certificate key,
# given as OpenSSL format private key file without passphrase protection.
#
# Default: <not defined>
#keyfile = /path/to/openssl-keyfile.pem

[usernamepassword]
# Use the following AD username in UPN notation.
#
# Default: <not defined>
#username = [email protected]

# Use the following AD password.
#
# Default: <not defined>
#password = ADpassword
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a good idea. I don't want AD passwords stored in a plain text file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not too fond of the idea either. However that concept was already in the part of the code for UsernamePassword authentication found in the master branch.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I didn't write that code ;-)
I think we could make this work with the creds stored in a keyring, if you want to pursue the idea.