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

CKAN 2.11 #115

Closed
wants to merge 18 commits into from
Closed
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
57 changes: 7 additions & 50 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.8'
python-version: '3.10'

- name: Install flake8
run: |
Expand All @@ -26,16 +26,16 @@ jobs:

- name: Lint with flake8
run: |
flake8 . --count --max-complexity=10 --max-line-length=127 --statistics --exclude ckan,ckanext-saml2auth
flake8 . --count --max-complexity=12 --max-line-length=127 --statistics --exclude ckan,ckanext-saml2auth

test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: [ '3.7', '3.8', '3.9']
ckan-version: ["2.9", "2.10"]
name: Python ${{ matrix.python-version }} extension test
python-version: ['3.9', '3.10']
ckan-version: ["2.10", "2.11"]
name: Python ${{ matrix.python-version }} CKAN ${{ matrix.ckan-version }} extension test

services:
postgresql:
Expand All @@ -61,9 +61,7 @@ jobs:
- 6379:6379

ckan-solr:
# Workflow level env variables are not addressable on job level, only on steps level
# image: ghcr.io/keitaroinc/ckan-solr-dev:{{ env.CKANVERSION }}
image: ghcr.io/keitaroinc/ckan-solr-dev:2.9
image: ckan/ckan-solr:2.10
ports:
- 8983:8983

Expand All @@ -90,46 +88,5 @@ jobs:

- name: Test with pytest
run: |
echo "Running SAML2AUTH tests"
pytest --ckan-ini=subdir/test.ini --cov=ckanext.saml2auth --disable-warnings ckanext/saml2auth/tests

- name: Coveralls
uses: AndreMiras/coveralls-python-action@develop
with:
parallel: true
flag-name: Python ${{ matrix.python-version }} Unit Test

publish:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.8'

- name: Install setup requirements
run: |
python -m pip install --upgrade setuptools wheel twine

- name: Build and package
run: |
python setup.py sdist bdist_wheel
twine check dist/*

- name: Publish package
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}

coveralls_finish:
needs: test
runs-on: ubuntu-latest
steps:
- name: Coveralls Finished
uses: AndreMiras/coveralls-python-action@develop
with:
parallel-finished: true
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
[![CI][]][1] [![Coverage][]][2] [![Gitter][]][3] [![Pypi][]][4] [![Python][]][5] [![CKAN][]][6]

# Temporary fork

**This is a temporary fork from OKFN** to work with CKAN 2.10 waiting for upstream repo at https://github.com/keitaroinc/ckanext-saml2auth to be updated.

# ckanext-saml2auth

A [CKAN](https://ckan.org) extension to enable Single Sign-On (SSO) for CKAN data portals via SAML2 Authentication.
Expand Down Expand Up @@ -135,6 +139,8 @@ Optional:
# Saml logout request preferred binding settings variable
# Default: urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST
ckanext.saml2auth.logout_expected_binding = urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST
# If you don't want to logout from external source you can use
ckanext.saml2auth.logout_expected_binding = skip-external-logout

# Default fallback endpoint to redirect to if no RelayState provided in the SAML Response
# Default: user.me (ie /dashboard)
Expand Down
5 changes: 3 additions & 2 deletions bin/setup-ckan.bash
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ cd ckan
ckan -c test-core.ini db init
cd -

echo "Installing ckanext-saml2auth and its requirements..."
python setup.py develop
echo "Installing saml2 requirements..."
pip install -r dev-requirements.txt
echo "Installing ckanext-saml2auth..."
pip install -e .

echo "Moving test.ini into a subdir..."
mkdir subdir
Expand Down
9 changes: 6 additions & 3 deletions ckanext/saml2auth/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,12 @@ def _perform_slo():

response = None

client = h.saml_client(
sp_config()
)
config = sp_config()
if config.get('logout_expected_binding') == 'skip-external-logout':
log.debug('Skipping external logout')
return

client = h.saml_client(config)
saml_session_info = get_saml_session_info(session)
subject_id = get_subject_id(session)

Expand Down
2 changes: 1 addition & 1 deletion ckanext/saml2auth/tests/responses/unsigned0.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<saml:NameID SPNameQualifier="{{ entity_id }}" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">_ce3d2948b4cf20146dee0a0b3dd6f69b6cf86f62d7</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData
NotOnOrAfter="2024-01-18T06:21:48Z"
NotOnOrAfter="2026-01-18T06:21:48Z"
Recipient="{{ recipient }}"
InResponseTo="ONELOGIN_4fee3b046395c4e751011e97f8900b5273d56685"/>
</saml:SubjectConfirmation>
Expand Down
5 changes: 4 additions & 1 deletion ckanext/saml2auth/tests/test_blueprint_get_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def _prepare_unsigned_response():
'entity_id': 'urn:gov:gsa:SAML:2.0.profiles:sp:sso:test:entity',
'destination': 'http://test.ckan.net/acs',
'recipient': 'http://test.ckan.net/acs',
'issue_instant': datetime.now().isoformat()
'issue_instant': datetime.now().isoformat(),
}
t = Template(unsigned_response)
final_response = t.render(**context)
Expand Down Expand Up @@ -118,6 +118,9 @@ def test_unsigned_request(self, app):
'SAMLResponse': encoded_response
}
response = app.post(url=url, params=data)
if response.status_code != 200:
assert False, f'Failed test_unsigned_request: {response.body}'
# Can&#39;t use response, too old (now=2024-07-31T17:42:38Z + slack=0 &gt; not_on_or_after=2024-01-18T06:21:48Z
assert 200 == response.status_code

def render_file(self, path, context, save_as=None):
Expand Down
46 changes: 46 additions & 0 deletions ckanext/saml2auth/tests/test_get_user_by_email.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import pytest
from types import SimpleNamespace
import ckan.model as model
from ckan.tests import factories
from ckan.plugins import toolkit
from ckanext.saml2auth.views.saml2auth import _get_user_by_email


@pytest.fixture
def tdv_data():
"""TestDatasetViews setup data"""
obj = SimpleNamespace()
obj.user1 = factories.User(
email='[email protected]',
plugin_extras={'saml2auth': {'saml_id': 'saml_id1'}}
)
obj.user2 = factories.User(
email='[email protected]',
plugin_extras={'saml2auth': {'saml_id': 'saml_id2'}}
)
return obj


@pytest.mark.usefixtures(u'clean_db', u'clean_index')
@pytest.mark.ckan_config(u'ckan.plugins', u'saml2auth')
class TestDatasetViews(object):
def test_get_user_by_email_empty(self, tdv_data):
""" The the function _get_user_by_email for empty response """
ret = _get_user_by_email('[email protected]')
assert ret is None

def test_get_user_by_email_ok(self, tdv_data):
""" The the function _get_user_by_email for empty response """
ret = _get_user_by_email(tdv_data.user1['email'])
assert ret is not None
assert ret['email'] == tdv_data.user1['email']

def test_get_user_by_email_multiple(self, tdv_data):
""" The the function _get_user_by_email for duplicated emails """
# Generate a duplciate email
user2 = model.User.get(tdv_data.user2['id'])
user2.email = tdv_data.user1['email'].upper()
model.Session.commit()

with pytest.raises(toolkit.ValidationError):
_get_user_by_email(tdv_data.user1['email'])
2 changes: 1 addition & 1 deletion ckanext/saml2auth/tests/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
def test_generate_password():
password = h.generate_password()
assert len(password) == 8
assert type(password) == str
assert isinstance(password, str)


def test_default_login_disabled_by_default():
Expand Down
21 changes: 14 additions & 7 deletions ckanext/saml2auth/views/saml2auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@
from flask import Blueprint, session
from saml2 import entity
from saml2.authn_context import requested_authn_context

from sqlalchemy.sql import func
import ckan.plugins.toolkit as toolkit
import ckan.model as model
import ckan.plugins as plugins
import ckan.lib.dictization.model_dictize as model_dictize
from ckan.lib import base
from ckan.lib import base, signals
from ckan.views.user import set_repoze_user
from ckan.common import config, g, request

Expand Down Expand Up @@ -76,13 +76,18 @@ def _get_user_by_saml_id(saml_id):

def _get_user_by_email(email):

user = model.User.by_email(email)
if user and isinstance(user, list):
user = user[0]
users = model.Session.query(model.User).filter(
func.lower(model.User.email) == func.lower(email)
).all()

h.activate_user_if_deleted(user)
if len(users) == 0:
return None
if len(users) > 1:
raise toolkit.ValidationError(f'Multiple users with the same email found {email}')

return _dictize_user(user) if user else None
user = users[0]
h.activate_user_if_deleted(user)
return _dictize_user(user)


def _update_user(user_dict):
Expand Down Expand Up @@ -227,6 +232,8 @@ def acs():
if error is not None:
log.error(error)
extra_vars = {u'code': [400], u'content': error}
# Trigger the CKAN failed login signal
signals.failed_login.send('Unknown_SAML2_user')
return base.render(u'error_document_template.html', extra_vars), 400

auth_response.get_identity()
Expand Down
1 change: 1 addition & 0 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
flake8 # for the CI build
pysaml2
packaging>=22.0
9 changes: 4 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,14 @@
# Versions should comply with PEP440. For a discussion on single-sourcing
# the version across setup.py and the project code, see
# http://packaging.python.org/en/latest/tutorial.html#version
version='1.3.0',
version='1.3.1',

description='''An extension to enable Single Sign On(SSO) for CKAN data portals via SAML2 Authentication.''',
long_description=long_description,
long_description_content_type='text/markdown',

# The project's main homepage.
url='https://github.com/keitaroinc/'\
'ckanext-saml2auth',
url='https://github.com/keitaroinc/ckanext-saml2auth',

# Author details
author='''Keitaro Inc''',
Expand All @@ -65,9 +64,9 @@
# Specify the Python versions you support here. In particular, ensure
# that you indicate whether you support Python 2, Python 3 or both.
'Programming Language :: Python :: 3 :: Only',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
],


Expand Down
Loading