Skip to content

Commit 21c68ce

Browse files
authored
Merge pull request #1 from keitaroinc/initial-implementation
Initial implementation
2 parents 5dedc9e + 9f32873 commit 21c68ce

21 files changed

Lines changed: 629 additions & 101 deletions

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,6 @@ coverage.xml
4040

4141
# Sphinx documentation
4242
docs/_build/
43+
44+
# Saml2 config
45+
idp.xml

.travis.yml

Lines changed: 9 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,16 @@
11
language: python
22
sudo: required
3-
4-
# use an older trusty image, because the newer images cause build errors with
5-
# psycopg2 that comes with CKAN<2.8:
6-
#  "Error: could not determine PostgreSQL version from '10.1'"
7-
# see https://github.com/travis-ci/travis-ci/issues/8897
8-
dist: trusty
9-
group: deprecated-2017Q4
10-
11-
# matrix
123
python:
13-
- 2.7
14-
env:
15-
- CKANVERSION=master
16-
- CKANVERSION=2.7
17-
- CKANVERSION=2.8
18-
19-
# tests
4+
- "3.8"
5+
env: CKANVERSION=2.9
206
services:
21-
- postgresql
22-
- redis-server
7+
- postgresql
8+
- redis
9+
- docker
2310
install:
24-
- bash bin/travis-build.bash
25-
- pip install coveralls
11+
- bash bin/travis-build.bash
12+
- pip install coveralls
13+
- pip freeze
2614
script: sh bin/travis-run.sh
2715
after_success:
28-
- coveralls
29-
30-
# additional jobs
31-
matrix:
32-
include:
33-
- name: "Flake8 on Python 3.7"
34-
dist: xenial # required for Python 3.7
35-
cache: pip
36-
install: pip install flake8
37-
script:
38-
- flake8 --version
39-
- flake8 . --count --max-complexity=10 --max-line-length=127 --statistics --exclude ckan,ckanext-saml2auth
40-
python: 3.7
41-
# overwrite matrix
42-
env:
43-
- FLAKE8=true
44-
- CKANVERSION=master
16+
- coveralls

README.rst

Lines changed: 68 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,18 @@
22
these badges work. The necessary Travis and Coverage config files have been
33
generated for you.
44
5-
.. image:: https://travis-ci.org/duskobogdanovski/ckanext-saml2auth.svg?branch=master
6-
:target: https://travis-ci.org/duskobogdanovski/ckanext-saml2auth
5+
.. image:: https://travis-ci.com/keitaroinc/ckanext-saml2auth.svg?branch=initial-implementation
6+
:target: https://travis-ci.com/keitaroinc/ckanext-saml2auth
77

8-
.. image:: https://coveralls.io/repos/duskobogdanovski/ckanext-saml2auth/badge.svg
9-
:target: https://coveralls.io/r/duskobogdanovski/ckanext-saml2auth
8+
.. image:: https://coveralls.io/repos/github/keitaroinc/ckanext-saml2auth/badge.svg?branch=initial-implementation
9+
:target: https://coveralls.io/github/keitaroinc/ckanext-saml2auth?branch=initial-implementation
1010

11-
.. image:: https://img.shields.io/pypi/v/ckanext-saml2auth.svg
12-
:target: https://pypi.org/project/ckanext-saml2auth/
13-
:alt: Latest Version
1411

15-
.. image:: https://img.shields.io/pypi/pyversions/ckanext-saml2auth.svg
16-
:target: https://pypi.org/project/ckanext-saml2auth/
17-
:alt: Supported Python versions
1812

19-
.. image:: https://img.shields.io/pypi/status/ckanext-saml2auth.svg
20-
:target: https://pypi.org/project/ckanext-saml2auth/
21-
:alt: Development Status
2213

23-
.. image:: https://img.shields.io/pypi/l/ckanext-saml2auth.svg
24-
:target: https://pypi.org/project/ckanext-saml2auth/
25-
:alt: License
26-
27-
=============
14+
==================
2815
ckanext-saml2auth
29-
=============
16+
==================
3017

3118
.. Put a description of your extension here:
3219
What does it do? What features does it have?
@@ -37,8 +24,7 @@ ckanext-saml2auth
3724
Requirements
3825
------------
3926

40-
For example, you might want to mention here which versions of CKAN this
41-
extension works with.
27+
This extension works with CKAN 2.9+.
4228

4329

4430
------------
@@ -51,19 +37,29 @@ Installation
5137
5238
To install ckanext-saml2auth:
5339

54-
1. Activate your CKAN virtual environment, for example::
40+
1. Install the required packages::
41+
42+
sudo apt install xmlsec1
43+
44+
45+
2. Activate your CKAN virtual environment, for example::
5546

5647
. /usr/lib/ckan/default/bin/activate
5748

58-
2. Install the ckanext-saml2auth Python package into your virtual environment::
49+
3. Install the ckanext-saml2auth Python package into your virtual environment::
5950

6051
pip install ckanext-saml2auth
6152

62-
3. Add ``saml2auth`` to the ``ckan.plugins`` setting in your CKAN
53+
54+
4. Install the python modules required by the extension (adjusting the path according to where ckanext-saml2auth was installed in the previous step)::
55+
56+
pip install -r requirements.txt
57+
58+
5. Add ``saml2auth`` to the ``ckan.plugins`` setting in your CKAN
6359
config file (by default the config file is located at
6460
``/etc/ckan/default/ckan.ini``).
6561

66-
4. Restart CKAN. For example if you've deployed CKAN with Apache on Ubuntu::
62+
6. Restart CKAN. For example if you've deployed CKAN with Apache on Ubuntu::
6763

6864
sudo service apache2 reload
6965

@@ -72,13 +68,51 @@ To install ckanext-saml2auth:
7268
Config settings
7369
---------------
7470

75-
None at present
71+
Required::
72+
73+
# Specifies the metadata location type
74+
# Options: local or remote
75+
ckanext.saml2auth.idp_metadata.location = remote
76+
77+
# Path to a local file accessible on the server the service runs on
78+
# Ignore this config if the idp metadata location is set to: remote
79+
ckanext.saml2auth.idp_metadata.local_path = /opt/metadata/idp.xml
80+
81+
# A remote URL serving aggregate metadata
82+
# Ignore this config if the idp metadata location is set to: local
83+
ckanext.saml2auth.idp_metadata.remote_url = https://kalmar2.org/simplesaml/module.php/aggregator/?id=kalmarcentral2&set=saml2
7684

77-
.. Document any optional config settings here. For example::
85+
# Path to a local file accessible on the server the service runs on
86+
# Ignore this config if the idp metadata location is set to: local
87+
ckanext.saml2auth.idp_metadata.remote_cert = /opt/metadata/kalmar2.cert
7888

79-
.. # The minimum number of hours to wait before re-checking a resource
80-
# (optional, default: 24).
81-
ckanext.saml2auth.some_setting = some_default_value
89+
# Corresponding SAML user field for firstname
90+
ckanext.saml2auth.user_firstname = firstname
91+
92+
# Corresponding SAML user field for lastname
93+
ckanext.saml2auth.user_lastname = lastname
94+
95+
# Corresponding SAML user field for email
96+
ckanext.saml2auth.user_email = email
97+
98+
99+
Optional::
100+
101+
# Configuration setting that enables CKAN's internal register/login functionality as well
102+
# Default: False
103+
ckanext.saml2auth.enable_ckan_internal_login = True
104+
105+
# List of email addresses from users that should be created as sysadmins (system administrators)
106+
ckanext.saml2auth.sysadmins_list = mail@domain.com mail2@domain.com mail3@domain.com
107+
108+
# Indicates that attributes that are not recognized (they are not configured in attribute-mapping),
109+
# will not be discarded.
110+
# Default: True
111+
ckanext.saml2auth.allow_unknown_attributes = False
112+
113+
# A list of string values that will be used to set the <NameIDFormat> element of the metadata of an entity.
114+
# Default: urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
115+
ckanext.saml2auth.sp.name_id_format = urn:oasis:names:tc:SAML:2.0:nameid-format:persistent urn:oasis:names:tc:SAML:2.0:nameid-format:transient
82116

83117

84118
----------------------
@@ -88,6 +122,8 @@ Developer installation
88122
To install ckanext-saml2auth for development, activate your CKAN virtualenv and
89123
do::
90124

125+
126+
sudo apt install xmlsec1
91127
git clone https://github.com/duskobogdanovski/ckanext-saml2auth.git
92128
cd ckanext-saml2auth
93129
python setup.py develop
@@ -108,9 +144,9 @@ To run the tests and produce a coverage report, first make sure you have
108144
pytest --ckan-ini=test.ini --cov=ckanext.saml2auth
109145

110146

111-
----------------------------------------
147+
--------------------------------------------
112148
Releasing a new version of ckanext-saml2auth
113-
----------------------------------------
149+
--------------------------------------------
114150

115151
ckanext-saml2auth should be available on PyPI as https://pypi.org/project/ckanext-saml2auth.
116152
To publish a new version to PyPI follow these steps:

bin/travis-build.bash

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ echo "This is travis-build.bash..."
55

66
echo "Installing the packages that CKAN requires..."
77
sudo apt-get update -qq
8-
sudo apt-get install solr-jetty
98

109
echo "Installing CKAN and its Python dependencies..."
1110
git clone https://github.com/ckan/ckan
@@ -42,16 +41,11 @@ sudo -u postgres psql -c "CREATE USER ckan_default WITH PASSWORD 'pass';"
4241
sudo -u postgres psql -c 'CREATE DATABASE ckan_test WITH OWNER ckan_default;'
4342

4443
echo "Setting up Solr..."
45-
# Solr is multicore for tests on ckan master, but it's easier to run tests on
46-
# Travis single-core. See https://github.com/ckan/ckan/issues/2972
47-
sed -i -e 's/solr_url.*/solr_url = http:\/\/127.0.0.1:8983\/solr/' ckan/test-core.ini
48-
printf "NO_START=0\nJETTY_HOST=127.0.0.1\nJETTY_PORT=8983\nJAVA_HOME=$JAVA_HOME" | sudo tee /etc/default/jetty
49-
sudo cp ckan/ckan/config/solr/schema.xml /etc/solr/conf/schema.xml
50-
sudo service jetty restart
44+
docker run --name ckan-solr -p 8983:8983 -d openknowledge/ckan-solr-dev:$CKANVERSION
5145

5246
echo "Initialising the database..."
5347
cd ckan
54-
paster db init -c test-core.ini
48+
ckan -c test-core.ini db init
5549
cd -
5650

5751
echo "Installing ckanext-saml2auth and its requirements..."

bin/travis-run.sh

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
11
#!/bin/sh -e
2-
set -ex
32

4-
flake8 --version
5-
# stop the build if there are Python syntax errors or undefined names
6-
flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics --exclude ckan,ckanext-saml2auth
3+
pytest --ckan-ini=subdir/test.ini --cov=ckanext.saml2auth --disable-warnings ckanext/saml2auth/tests
74

8-
pytest --ckan-ini=subdir/test.ini \
9-
--cov=ckanext.saml2auth
10-
11-
# strict linting
125
flake8 . --count --max-complexity=10 --max-line-length=127 --statistics --exclude ckan,ckanext-saml2auth

ckanext/saml2auth/helpers.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# encoding: utf-8
2+
import logging
3+
import string
4+
import secrets
5+
from six import text_type
6+
7+
from saml2.client import Saml2Client
8+
from saml2.config import Config as Saml2Config
9+
10+
import ckan.model as model
11+
import ckan.authz as authz
12+
from ckan.common import config, asbool, aslist
13+
14+
log = logging.getLogger(__name__)
15+
16+
17+
def saml_client(config):
18+
sp_config = Saml2Config()
19+
sp_config.load(config)
20+
client = Saml2Client(config=sp_config)
21+
return client
22+
23+
24+
def generate_password():
25+
alphabet = string.ascii_letters + string.digits
26+
password = ''.join(secrets.choice(alphabet) for i in range(8))
27+
return password
28+
29+
30+
def is_default_login_enabled():
31+
return asbool(
32+
config.get('ckanext.saml2auth.enable_ckan_internal_login',
33+
False))
34+
35+
36+
def update_user_sysadmin_status(username, email):
37+
sysadmins_list = aslist(
38+
config.get('ckanext.saml2auth.sysadmins_list'))
39+
user = model.User.by_name(text_type(username))
40+
sysadmin = authz.is_sysadmin(username)
41+
42+
if sysadmin and email not in sysadmins_list:
43+
user.sysadmin = False
44+
model.Session.add(user)
45+
model.Session.commit()
46+
elif not sysadmin and email in sysadmins_list:
47+
user.sysadmin = True
48+
model.Session.add(user)
49+
model.Session.commit()
50+
51+
52+
def activate_user_if_deleted(userobj):
53+
u'''Reactivates deleted user.'''
54+
if userobj.is_deleted():
55+
userobj.activate()
56+
userobj.commit()
57+
log.info(u'User {} reactivated'.format(userobj.name))

ckanext/saml2auth/plugin.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,49 @@
1+
# encoding: utf-8
12
import ckan.plugins as plugins
23
import ckan.plugins.toolkit as toolkit
34

5+
from ckanext.saml2auth.views.saml2auth import saml2auth
6+
from ckanext.saml2auth import helpers as h
7+
48

59
class Saml2AuthPlugin(plugins.SingletonPlugin):
610
plugins.implements(plugins.IConfigurer)
11+
plugins.implements(plugins.IBlueprint)
12+
plugins.implements(plugins.IConfigurable)
13+
plugins.implements(plugins.ITemplateHelpers)
14+
15+
# ITemplateHelpers
16+
17+
def get_helpers(self):
18+
return {
19+
'is_default_login_enabled':
20+
h.is_default_login_enabled
21+
}
22+
23+
# IConfigurable
24+
25+
def configure(self, config):
26+
# Certain config options must exists for the plugin to work. Raise an
27+
# exception if they're missing.
28+
missing_config = "{0} is not configured. Please amend your .ini file."
29+
config_options = (
30+
'ckanext.saml2auth.idp_metadata.local_path',
31+
'ckanext.saml2auth.user_firstname',
32+
'ckanext.saml2auth.user_lastname',
33+
'ckanext.saml2auth.user_email'
34+
)
35+
for option in config_options:
36+
if not config.get(option, None):
37+
raise RuntimeError(missing_config.format(option))
38+
39+
# IBlueprint
40+
41+
def get_blueprint(self):
42+
return [saml2auth]
743

844
# IConfigurer
945

1046
def update_config(self, config_):
1147
toolkit.add_template_directory(config_, 'templates')
1248
toolkit.add_public_directory(config_, 'public')
13-
toolkit.add_resource('fanstatic',
14-
'saml2auth')
49+
toolkit.add_resource('fanstatic', 'saml2auth')

0 commit comments

Comments
 (0)