Skip to content

Commit

Permalink
Merge pull request #1 from keitaroinc/initial-implementation
Browse files Browse the repository at this point in the history
Initial implementation
  • Loading branch information
mbocevski authored Nov 17, 2020
2 parents 5dedc9e + 9f32873 commit 21c68ce
Show file tree
Hide file tree
Showing 21 changed files with 629 additions and 101 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,6 @@ coverage.xml

# Sphinx documentation
docs/_build/

# Saml2 config
idp.xml
46 changes: 9 additions & 37 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,44 +1,16 @@
language: python
sudo: required

# use an older trusty image, because the newer images cause build errors with
# psycopg2 that comes with CKAN<2.8:
#  "Error: could not determine PostgreSQL version from '10.1'"
# see https://github.com/travis-ci/travis-ci/issues/8897
dist: trusty
group: deprecated-2017Q4

# matrix
python:
- 2.7
env:
- CKANVERSION=master
- CKANVERSION=2.7
- CKANVERSION=2.8

# tests
- "3.8"
env: CKANVERSION=2.9
services:
- postgresql
- redis-server
- postgresql
- redis
- docker
install:
- bash bin/travis-build.bash
- pip install coveralls
- bash bin/travis-build.bash
- pip install coveralls
- pip freeze
script: sh bin/travis-run.sh
after_success:
- coveralls

# additional jobs
matrix:
include:
- name: "Flake8 on Python 3.7"
dist: xenial # required for Python 3.7
cache: pip
install: pip install flake8
script:
- flake8 --version
- flake8 . --count --max-complexity=10 --max-line-length=127 --statistics --exclude ckan,ckanext-saml2auth
python: 3.7
# overwrite matrix
env:
- FLAKE8=true
- CKANVERSION=master
- coveralls
100 changes: 68 additions & 32 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,18 @@
these badges work. The necessary Travis and Coverage config files have been
generated for you.
.. image:: https://travis-ci.org/duskobogdanovski/ckanext-saml2auth.svg?branch=master
:target: https://travis-ci.org/duskobogdanovski/ckanext-saml2auth
.. image:: https://travis-ci.com/keitaroinc/ckanext-saml2auth.svg?branch=initial-implementation
:target: https://travis-ci.com/keitaroinc/ckanext-saml2auth

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

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

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

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

.. image:: https://img.shields.io/pypi/l/ckanext-saml2auth.svg
:target: https://pypi.org/project/ckanext-saml2auth/
:alt: License

=============
==================
ckanext-saml2auth
=============
==================

.. Put a description of your extension here:
What does it do? What features does it have?
Expand All @@ -37,8 +24,7 @@ ckanext-saml2auth
Requirements
------------

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


------------
Expand All @@ -51,19 +37,29 @@ Installation
To install ckanext-saml2auth:

1. Activate your CKAN virtual environment, for example::
1. Install the required packages::

sudo apt install xmlsec1


2. Activate your CKAN virtual environment, for example::

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

2. Install the ckanext-saml2auth Python package into your virtual environment::
3. Install the ckanext-saml2auth Python package into your virtual environment::

pip install ckanext-saml2auth

3. Add ``saml2auth`` to the ``ckan.plugins`` setting in your CKAN

4. Install the python modules required by the extension (adjusting the path according to where ckanext-saml2auth was installed in the previous step)::

pip install -r requirements.txt

5. Add ``saml2auth`` to the ``ckan.plugins`` setting in your CKAN
config file (by default the config file is located at
``/etc/ckan/default/ckan.ini``).

4. Restart CKAN. For example if you've deployed CKAN with Apache on Ubuntu::
6. Restart CKAN. For example if you've deployed CKAN with Apache on Ubuntu::

sudo service apache2 reload

Expand All @@ -72,13 +68,51 @@ To install ckanext-saml2auth:
Config settings
---------------

None at present
Required::

# Specifies the metadata location type
# Options: local or remote
ckanext.saml2auth.idp_metadata.location = remote

# Path to a local file accessible on the server the service runs on
# Ignore this config if the idp metadata location is set to: remote
ckanext.saml2auth.idp_metadata.local_path = /opt/metadata/idp.xml

# A remote URL serving aggregate metadata
# Ignore this config if the idp metadata location is set to: local
ckanext.saml2auth.idp_metadata.remote_url = https://kalmar2.org/simplesaml/module.php/aggregator/?id=kalmarcentral2&set=saml2

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

.. # The minimum number of hours to wait before re-checking a resource
# (optional, default: 24).
ckanext.saml2auth.some_setting = some_default_value
# Corresponding SAML user field for firstname
ckanext.saml2auth.user_firstname = firstname

# Corresponding SAML user field for lastname
ckanext.saml2auth.user_lastname = lastname

# Corresponding SAML user field for email
ckanext.saml2auth.user_email = email


Optional::

# Configuration setting that enables CKAN's internal register/login functionality as well
# Default: False
ckanext.saml2auth.enable_ckan_internal_login = True

# List of email addresses from users that should be created as sysadmins (system administrators)
ckanext.saml2auth.sysadmins_list = mail@domain.com mail2@domain.com mail3@domain.com

# Indicates that attributes that are not recognized (they are not configured in attribute-mapping),
# will not be discarded.
# Default: True
ckanext.saml2auth.allow_unknown_attributes = False

# A list of string values that will be used to set the <NameIDFormat> element of the metadata of an entity.
# Default: urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
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


----------------------
Expand All @@ -88,6 +122,8 @@ Developer installation
To install ckanext-saml2auth for development, activate your CKAN virtualenv and
do::


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


----------------------------------------
--------------------------------------------
Releasing a new version of ckanext-saml2auth
----------------------------------------
--------------------------------------------

ckanext-saml2auth should be available on PyPI as https://pypi.org/project/ckanext-saml2auth.
To publish a new version to PyPI follow these steps:
Expand Down
10 changes: 2 additions & 8 deletions bin/travis-build.bash
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ echo "This is travis-build.bash..."

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

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

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

echo "Initialising the database..."
cd ckan
paster db init -c test-core.ini
ckan -c test-core.ini db init
cd -

echo "Installing ckanext-saml2auth and its requirements..."
Expand Down
9 changes: 1 addition & 8 deletions bin/travis-run.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
#!/bin/sh -e
set -ex

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

pytest --ckan-ini=subdir/test.ini \
--cov=ckanext.saml2auth

# strict linting
flake8 . --count --max-complexity=10 --max-line-length=127 --statistics --exclude ckan,ckanext-saml2auth
57 changes: 57 additions & 0 deletions ckanext/saml2auth/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# encoding: utf-8
import logging
import string
import secrets
from six import text_type

from saml2.client import Saml2Client
from saml2.config import Config as Saml2Config

import ckan.model as model
import ckan.authz as authz
from ckan.common import config, asbool, aslist

log = logging.getLogger(__name__)


def saml_client(config):
sp_config = Saml2Config()
sp_config.load(config)
client = Saml2Client(config=sp_config)
return client


def generate_password():
alphabet = string.ascii_letters + string.digits
password = ''.join(secrets.choice(alphabet) for i in range(8))
return password


def is_default_login_enabled():
return asbool(
config.get('ckanext.saml2auth.enable_ckan_internal_login',
False))


def update_user_sysadmin_status(username, email):
sysadmins_list = aslist(
config.get('ckanext.saml2auth.sysadmins_list'))
user = model.User.by_name(text_type(username))
sysadmin = authz.is_sysadmin(username)

if sysadmin and email not in sysadmins_list:
user.sysadmin = False
model.Session.add(user)
model.Session.commit()
elif not sysadmin and email in sysadmins_list:
user.sysadmin = True
model.Session.add(user)
model.Session.commit()


def activate_user_if_deleted(userobj):
u'''Reactivates deleted user.'''
if userobj.is_deleted():
userobj.activate()
userobj.commit()
log.info(u'User {} reactivated'.format(userobj.name))
39 changes: 37 additions & 2 deletions ckanext/saml2auth/plugin.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,49 @@
# encoding: utf-8
import ckan.plugins as plugins
import ckan.plugins.toolkit as toolkit

from ckanext.saml2auth.views.saml2auth import saml2auth
from ckanext.saml2auth import helpers as h


class Saml2AuthPlugin(plugins.SingletonPlugin):
plugins.implements(plugins.IConfigurer)
plugins.implements(plugins.IBlueprint)
plugins.implements(plugins.IConfigurable)
plugins.implements(plugins.ITemplateHelpers)

# ITemplateHelpers

def get_helpers(self):
return {
'is_default_login_enabled':
h.is_default_login_enabled
}

# IConfigurable

def configure(self, config):
# Certain config options must exists for the plugin to work. Raise an
# exception if they're missing.
missing_config = "{0} is not configured. Please amend your .ini file."
config_options = (
'ckanext.saml2auth.idp_metadata.local_path',
'ckanext.saml2auth.user_firstname',
'ckanext.saml2auth.user_lastname',
'ckanext.saml2auth.user_email'
)
for option in config_options:
if not config.get(option, None):
raise RuntimeError(missing_config.format(option))

# IBlueprint

def get_blueprint(self):
return [saml2auth]

# IConfigurer

def update_config(self, config_):
toolkit.add_template_directory(config_, 'templates')
toolkit.add_public_directory(config_, 'public')
toolkit.add_resource('fanstatic',
'saml2auth')
toolkit.add_resource('fanstatic', 'saml2auth')
Loading

0 comments on commit 21c68ce

Please sign in to comment.