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

Add OpenID Connect Token authenticator #167

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
61 changes: 61 additions & 0 deletions custodia/httpd/authenticators.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

from cryptography.hazmat.primitives import constant_time

import requests

from custodia import log
from custodia.plugin import HTTPAuthenticator, PluginOption

Expand Down Expand Up @@ -131,3 +133,62 @@ def handle(self, request):
self.audit_svc_access(log.AUDIT_SVC_AUTH_FAIL,
request['client_id'], dn)
return False


class OpenIDCTokenAuth(HTTPAuthenticator):
Copy link
Member

Choose a reason for hiding this comment

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

Please add a doc string with an example how to configure and use this plugin with e.g. Ipsilon.

token_info_url = PluginOption(str, None,
Copy link
Member

Choose a reason for hiding this comment

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

You can use REQUIRED to make an option mandatory

'URL for getting token information')
client_id = PluginOption(str, None,
'Client ID for verifying tokens')
client_secret = PluginOption(str, None,
'Client Secret for verifying tokens')
scope = PluginOption(str, 'custodia', 'OAuth2 scope to require')

def _get_token_info(self, token):
return requests.post(self.token_info_url,
Copy link
Member

Choose a reason for hiding this comment

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

Other plugins accept a CA cert argument to customize TLS verification. We could have global option for trusted CA cert, too.

data={'client_id': self.client_id,
'client_secret': self.client_secret,
'token': token,
'token_type_hint': 'Bearer'}).json()

def handle(self, request):
token = None
if 'Authorization' in request['headers']:
hdr = request['headers']['Authorization']
if hdr.startswith('Bearer '):
self.logger.debug('Bearer token provided in header')
token = hdr[len('Bearer '):]
else:
self.logger.debug('Unrecognized Authorization header')
return False
elif request.get('access_token'):
self.logger.debug('Token provided in form')
token = request.get('access_token')
Copy link
Member

Choose a reason for hiding this comment

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

request['access_token]

else:
self.logger.debug('Missing any credentials in request')
return False

if not token:
Copy link
Member

Choose a reason for hiding this comment

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

Is it necessary to check token again?

self.logger.debug('No token')
return False

try:
tokeninfo = self._get_token_info(token)
except:
Copy link
Member

Choose a reason for hiding this comment

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

Please don't use a bare except. except Exception

self.logger.debug('Error getting token information',
exc_info=True)
return False

aud = tokeninfo['aud']
if isinstance(aud, list) and self.client_id not in aud:
self.logger.debug('My client ID not in audience list')
return False
elif self.client_id != aud:
self.logger.debug('Client ID is not audience')
return False

if self.scope not in tokeninfo['scope'].split(' '):
self.logger.debug('Required scope not found')
return False

return True
5 changes: 5 additions & 0 deletions docs/source/plugins/authenticators.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,8 @@ Authenticators
:undoc-members:
:show-inheritance:

.. autoclass:: custodia.httpd.authenticators.OpenIDCTokenAuth
:members:
:undoc-members:
:show-inheritance:

1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ def run(self):
'SimpleAuthKeys = custodia.httpd.authenticators:SimpleAuthKeys',
('SimpleClientCertAuth = '
'custodia.httpd.authenticators:SimpleClientCertAuth'),
'OIDCTokenAuth = custodia.httpd.authenticators:OpenIDCTokenAuth',
]

custodia_authorizers = [
Expand Down