Skip to content
Snippets Groups Projects
Commit 7c7f900b authored by Jorrit Schaap's avatar Jorrit Schaap
Browse files

Merge branch 'TMSS-175' into 'master'

Resolve TMSS-175

Closes TMSS-175

See merge request !160
parents e9f81a68 129f18cf
No related branches found
No related tags found
1 merge request!160Resolve TMSS-175
Showing
with 775 additions and 0 deletions
version: "2"
services:
tmss_test:
build:
context: .
dockerfile: tmss_testenv_Dockerfile
container_name: tmss_test
ports:
- "8000:8000"
# - "3003:3003"
networks:
- "tmss"
volumes:
- static_volume:/staticfiles
environment:
- OIDC_ENDPOINT_HOST=172.25.0.10
- OIDC_RP_CLIENT_ID=1
tmss_test_nginx:
build:
context: .
dockerfile: tmss_nginx_Dockerfile
container_name: tmss_test_nginx
ports:
- "80:80"
networks:
- "tmss"
volumes:
- static_volume:/staticfiles
tmss_test_oidc:
build:
context: ./docker-test-mozilla-django-oidc/
dockerfile: dockerfiles/oidc_testprovider
container_name: tmss_test_oidc
ports:
- "8088:8088"
networks:
tmss:
ipv4_address: 172.25.0.10
networks:
tmss:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.25.0.0/16
gateway: 172.25.0.1
volumes:
static_volume:
\ No newline at end of file
# Python CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-python/ for more details
#
version: 2
jobs:
build:
docker:
- image: mozilla/cidockerbases:docker-latest
working_directory: /
steps:
- run:
name: Get info
command: uname -v
- setup_remote_docker
- run:
name: Get info
command: docker info
- run:
name: Install essential packages
command: apt-get install make
- checkout:
path: /oidc_testprovider
- run:
name: Build Docker images
working_directory: /oidc_testprovider
command: |
make build
- run:
name: Push to Dockerhub on tag
working_directory: /oidc_testprovider
command: |
function retry {
set +e
local n=0
local max=3
while true; do
"$@" && break || {
if [[ $n -lt $max ]]; then
((n++))
echo "Command failed. Attempt $n/$max:"
else
echo "Failed after $n attempts."
exit 1
fi
}
done
set -e
}
# Namespace on dockerhub to push:
# https://hub.docker.com/u/mozilla/oidc-testprovider
export DOCKER_NAMESPACE=mozilla/oidc-testprovider
export IMAGES=(oidc_e2e_setup_py2 oidc_e2e_setup_py3 oidc_testprovider oidc_testrp_py2 oidc_testrp_py3 oidc_testrunner)
# If a tag was pushed to github, push tagged images and latest
# images to Dockerhub
if [ -n "${CIRCLE_TAG}" ]; then
# Log into Dockerhub
echo "${DOCKER_PASS}" | docker login -u="${DOCKER_USER}" --password-stdin
for IMAGE in "${IMAGES[@]}"
do
echo ""
echo ">>> WORKING ON ${IMAGE}..."
echo ""
# Tag and push tagged image.
retry docker tag "${IMAGE}:latest" "${DOCKER_NAMESPACE}:${IMAGE}-${CIRCLE_TAG}"
retry docker push "${DOCKER_NAMESPACE}:${IMAGE}-${CIRCLE_TAG}"
# Tag and push latest image.
retry docker tag "${IMAGE}:latest" "${DOCKER_NAMESPACE}:${IMAGE}-latest"
retry docker push "${DOCKER_NAMESPACE}:${IMAGE}-latest"
done
fi
workflows:
version: 2
# workflow jobs are _not_ run in tag builds by default
# we use filters to whitelist jobs that should be run for tags
# workflow jobs are run in _all_ branch builds by default
# we use filters to blacklist jobs that shouldn't be run for a branch
# see: https://circleci.com/docs/2.0/workflows/#git-tag-job-execution
build-test-push:
jobs:
- build:
filters:
tags:
only: /.*/
HISTORY
=======
v0.9.3 (October 23rd, 2019)
---------------------------
Bugs:
* fix docker push code
v0.9.2 (October 22nd, 2019)
---------------------------
No substantive changes. Doing a new tag so as to push images to dockerhub.
v0.9.1 (October 22nd, 2019)
---------------------------
Bugs:
* fix `build` and `pull` rules in Makefile to use the correct tags
v0.9.0 (October 22nd, 2019)
---------------------------
First tagged release.
Features:
* new `createuser` command in `oidc_testprovider` image
* redid how images are tagged and we're now pushing them to dockerhub
in the `mozilla` user
DEFAULT_GOAL := help
NS ?= mozilla/oidc-testprovider
IMAGES := oidc_testprovider oidc_testrunner oidc_testrp_py2 oidc_testrp_py3 oidc_e2e_setup_py2 oidc_e2e_setup_py3
BUILD := $(addprefix build-,${IMAGES})
PULL := $(addprefix pull-,$(IMAGES))
CLEAN := $(addprefix clean-,$(IMAGES))
.PHONY: help
help:
@fgrep -h "##" Makefile | fgrep -v fgrep | sed 's/\(.*\):.*##/\1:/'
.PHONY: build
build: ${BUILD} ## Build all images
.PHONY: pull
pull: ${PULL} ## Pull all -latest images
.PHONY: clean
clean: ${CLEAN} ## Clean images and other artifacts
.PHONY: ${BUILD}
${BUILD}: build-%:
docker build -t $* -f dockerfiles/$* .
.PHONY: ${PULL}
${PULL}: pull-%:
docker pull ${NS}:$*-latest
.PHONY: ${CLEAN}
${CLEAN}: clean-%:
docker rmi ${NS}/$(subst _py,:py,$(*))
docker rmi $(subst _py,:py,$(*))
# docker-test-mozilla-django-oidc
The purpose of these docker images is to setup a local environment to develop and test
`mozilla-django-oidc`.
## oidc-testprovider
https://hub.docker.com/r/mozilla/oidc-testprovider/tags?name=testprovider
* Provides a docker image for an OIDC OP with preconfigured OIDC client IDs and secrets
* OIDC provider endpoint is exposed in port `8080`
* Provides a Django management command for creating users
* Uses `django-oidc-provider`
### Usage
In order for this setup to work `testprovider`, `testrp` hostnames should resolve to the
IP of the docker image (for local development it's `127.0.0.1`).
You can add the resolution to your `/etc/hosts` file.
You can also use [nip.io](http://nip.io/). For example, if you name the service
"oidcprovider", then you could have these three variables:
```
OIDC_OP_AUTHORIZATION_ENDPOINT=http://oidcprovider.127.0.0.1.nip.io:8080/openid/authorize
OIDC_OP_TOKEN_ENDPOINT=http://oidcprovider.127.0.0.1.nip.io:8080/openid/token
OIDC_OP_USER_ENDPOINT=http://oidcprovider.127.0.0.1.nip.io:8080/openid/userinfo
```
### Example setup
`docker-compose.yml`
```
version: '3'
services:
testprovider:
image: mozilla/oidc-testprovider:oidc_testprovider-v0.9.3
ports:
- "8080:8080"
```
### Creating users in the container
The `testprovider` image has a Django management command for creating users in
the OIDC provider. This lets you create users on the command line.
With an already running `testprovider` container run:
```
docker-compose exec testprovider manage.py createuser USERNAME PASSWORD EMAIL
```
## Other images
All images are pushed to: https://hub.docker.com/r/mozilla/oidc-testprovider
* `oidc_testprovider` (See above)
* `oidc_testrunner`
* `oidc_testrp_py{2,3}`
* Test django project preconfigured to work with `testprovider`
* Uses `mozilla-django-oidc` as an authentication backend
* Test RP is exposed in port `8081`
* Builds based in both python 2/3
* Environment variables
* `TEST_OIDC_ALGO={hs,rs}`
* `oidc_e2e_setup_py{2,3}`
* Dockerized setup for e2e testing of mozilla-django-oidc
### Example setup for oidc_testrp
`docker-compose.yml`
```
version: '3'
services:
testrp:
image: mozilla/oidc-testprovider:oidc_testrp_py3-v0.9.3
ports:
- "8081:8081"
environment:
- TEST_OIDC_ALGO=hs
```
## Development
We use `make` to automate the docker image workflow.
For more info run `make help`.
Pushing a tag to GitHub will trigger building images and uploading them
to Dockerhub.
version: '3'
services:
testprovider:
image: mozilla/oidc-testprovider:oidc_testprovider-v0.9.3
ports:
- "8080:8080"
FROM python:2-stretch
EXPOSE 8080 8081
RUN pip install virtualenv
RUN virtualenv /testrp_env
RUN virtualenv /testprovider_env
COPY testprovider /testprovider/
COPY testrp /testrp/
RUN . /testprovider_env/bin/activate && pip install -r /testprovider/requirements.txt
RUN . /testrp_env/bin/activate && pip install -r /testrp/requirements.txt
# Install python and python dependencies
RUN apt-get update && \
apt-get install -y wait-for-it
# Install firefox
RUN apt-get install -y --no-install-recommends firefox-esr && \
wget "https://download.mozilla.org/?product=firefox-latest&os=linux64&lang=en-US" -O /tmp/firefox.tar.bz2 && \
tar xvf /tmp/firefox.tar.bz2 -C /opt && \
rm /usr/bin/firefox && \
ln -s /opt/firefox/firefox /usr/bin/firefox
# Install geckodriver
RUN wget "https://github.com/mozilla/geckodriver/releases/download/v0.23.0/geckodriver-v0.23.0-linux32.tar.gz" -O /tmp/geckodriver.tar.gz && \
tar xvf /tmp/geckodriver.tar.gz -C /opt && \
ln -s /opt/geckodriver /usr/bin/geckodriver
FROM python:3.6-stretch
EXPOSE 8080 8081
RUN pip install virtualenv
RUN virtualenv /testrp_env
RUN virtualenv /testprovider_env
COPY testprovider /testprovider/
COPY testrp /testrp/
RUN . /testprovider_env/bin/activate && pip install -r /testprovider/requirements.txt
RUN . /testrp_env/bin/activate && pip install -r /testrp/requirements.txt
# Install python and python dependencies
RUN apt-get update && \
apt-get install -y wait-for-it
# Install firefox
RUN apt-get install -y --no-install-recommends firefox-esr && \
wget "https://download.mozilla.org/?product=firefox-latest&os=linux64&lang=en-US" -O /tmp/firefox.tar.bz2 && \
tar xvf /tmp/firefox.tar.bz2 -C /opt && \
rm /usr/bin/firefox && \
ln -s /opt/firefox/firefox /usr/bin/firefox
# Install geckodriver
RUN wget "https://github.com/mozilla/geckodriver/releases/download/v0.23.0/geckodriver-v0.23.0-linux32.tar.gz" -O /tmp/geckodriver.tar.gz && \
tar xvf /tmp/geckodriver.tar.gz -C /opt && \
ln -s /opt/geckodriver /usr/bin/geckodriver
FROM python:3.6
EXPOSE 8088
WORKDIR /code
COPY testprovider/requirements.txt /code/
RUN pip install -r requirements.txt
COPY testprovider /code/
CMD ./bin/run.sh
FROM python:2-stretch
EXPOSE 8081
COPY testrp /code/
WORKDIR /code
RUN pip install -r requirements.txt
CMD ./bin/run.sh
FROM python:3-stretch
EXPOSE 8081
COPY testrp /code/
WORKDIR /code
RUN pip install -r requirements.txt
CMD ./bin/run.sh
FROM python:3-stretch
# Install python and python dependencies
RUN apt-get update && \
apt-get install -y wait-for-it && \
pip install six splinter
# Install firefox
RUN apt-get install -y --no-install-recommends firefox-esr && \
wget "https://download.mozilla.org/?product=firefox-latest&os=linux64&lang=en-US" -O /tmp/firefox.tar.bz2 && \
tar xvf /tmp/firefox.tar.bz2 -C /opt && \
rm /usr/bin/firefox && \
ln -s /opt/firefox/firefox /usr/bin/firefox
# Install geckodriver
RUN wget "https://github.com/mozilla/geckodriver/releases/download/v0.23.0/geckodriver-v0.23.0-linux32.tar.gz" -O /tmp/geckodriver.tar.gz && \
tar xvf /tmp/geckodriver.tar.gz -C /opt && \
ln -s /opt/geckodriver /usr/bin/geckodriver
#!/bin/sh
if [ -n "$OIDC_OP_CALLBACK_ENDPOINT" ]; then sed -i "s|http://localhost:8000/oidc/callback/|$OIDC_OP_CALLBACK_ENDPOINT|" fixtures.json; fi
python manage.py migrate --noinput
python manage.py loaddata fixtures.json
python ./manage.py createuser paulus pauluspass paulus@localhost
python manage.py runserver 0.0.0.0:8088
[
{
"model": "sites.site",
"pk": 1,
"fields": {
"domain": "testprovider:8088",
"name": "testprovider"
}
},
{
"model": "oidc_provider.responsetype",
"pk": 1,
"fields": {
"value": "code",
"description": "code (Authorization Code Flow)"
}
},
{
"model": "oidc_provider.responsetype",
"pk": 2,
"fields": {
"value": "id_token",
"description": "id_token (Implicit Flow)"
}
},
{
"model": "oidc_provider.responsetype",
"pk": 3,
"fields": {
"value": "id_token token",
"description": "id_token token (Implicit Flow)"
}
},
{
"model": "oidc_provider.responsetype",
"pk": 4,
"fields": {
"value": "code token",
"description": "code token (Hybrid Flow)"
}
},
{
"model": "oidc_provider.responsetype",
"pk": 5,
"fields": {
"value": "code id_token",
"description": "code id_token (Hybrid Flow)"
}
},
{
"model": "oidc_provider.responsetype",
"pk": 6,
"fields": {
"value": "code id_token token",
"description": "code id_token token (Hybrid Flow)"
}
},
{
"model": "oidc_provider.client",
"pk": 1,
"fields": {
"name": "testrpHS256",
"owner": null,
"client_type": "confidential",
"client_id": "1",
"client_secret": "secret",
"jwt_alg": "HS256",
"date_created": "2017-11-10",
"website_url": "",
"terms_url": "",
"contact_email": "",
"logo": "",
"reuse_consent": true,
"require_consent": true,
"_redirect_uris": "http://localhost/oidc/callback/",
"_post_logout_redirect_uris": "",
"_scope": "",
"response_types": [
1
]
}
},
{
"model": "oidc_provider.client",
"pk": 2,
"fields": {
"name": "testrpHS256",
"owner": null,
"client_type": "confidential",
"client_id": "2",
"client_secret": "secret",
"jwt_alg": "HS256",
"date_created": "2017-11-10",
"website_url": "",
"terms_url": "",
"contact_email": "",
"logo": "",
"reuse_consent": true,
"require_consent": true,
"_redirect_uris": "http://localhost:8000/oidc/callback/",
"_post_logout_redirect_uris": "",
"_scope": "",
"response_types": [
1
]
}
},
{
"model": "oidc_provider.client",
"pk": 3,
"fields": {
"name": "testrpRS256",
"owner": null,
"client_type": "confidential",
"client_id": "3",
"client_secret": "secret",
"jwt_alg": "RS256",
"date_created": "2017-11-10",
"website_url": "",
"terms_url": "",
"contact_email": "",
"logo": "",
"reuse_consent": true,
"require_consent": true,
"_redirect_uris": "http://localhost:8000/oidc/callback/",
"_post_logout_redirect_uris": "",
"_scope": "",
"response_types": [
1
]
}
},
{
"model": "oidc_provider.rsakey",
"pk": 3,
"fields": {
"key": "-----BEGIN RSA PRIVATE KEY-----\nMIICXAIBAAKBgQDAAgiIdiJG7GSMKTRbnGjWpHp1ulJ43/iQjDywWh5MP3in2PK8\nPVI6ItxIFLV81nWZMymA7hjfP7adOlxKY6rI+fExn8cTimI3W/oX6mHrPXm52uj/\nwe839pxxkeD7cmWgaif9Sujuy5AHUuUM1BTlO55POHkmhWyYMKC2P29qgQIDAQAB\nAoGAUHdJri6b1M8yoA6Qk6frw7AwZfAMqf1qxOEQefN6aQfcf7MKntqwAA8l88tB\n96xEokxvo0mlAMJJvIB9tusn4dIHKpmQGacQWVd/KONxPkvyuGgQXX5KCusZTbg7\ni6YQM52RGbExVFWLdGYJRBvzyfRkWX0b4LiderPZUiD6J/UCQQDZIgnLqYyGw3Ro\nnNboWYyOtLhKMF59f/0aSMXLlWdsnFG8kVm/7tw6jcDBalELci/+ExL2JACGwDea\n8DpvWiEDAkEA4mCovWmMDiS8tQCeY5NDic1wMp51+Ya8RX47bvb5F+X7SSE9L87y\n6eU9zVBSY8F+9npkvrxoU9PlKbS3Lzz1KwJAZ5/8BsuS+lnbe3Wmhtr93rlW3mk5\nHzHu7BVg+GkEI+xygcjoiVYImpU+MdB4fzrutpYJzZie+7BOmU4exTfBWwJBAKj+\nN3mO/Xrhee41VAhJuzV4I7XmDXQFXS8TmRKxVCq/COQC6EZ0W2q4M3a964OEw18E\n54hr5gYOPRjxS378JpkCQDjKw2Vyw0S0M8O2hOGuNsUtlGApYKt2iA41jGUf7bvO\nWz/tQuEIXQMd4e9zxNxOzPJOtjR1gyPZyi/FvsgDJDU=\n-----END RSA PRIVATE KEY-----"
}
}
]
#!/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "oidcprovider.settings")
try:
from django.core.management import execute_from_command_line
except ImportError:
# The above import may fail for some other reason. Ensure that the
# issue is really that Django is missing to avoid masking other
# exceptions on Python 2.
try:
import django
except ImportError:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
)
raise
execute_from_command_line(sys.argv)
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
"""
Create a user in the OIDC provider.
"""
from django.contrib.auth.models import User
from django.core.management.base import BaseCommand
class Command(BaseCommand):
help = "Create a user in the OIDC provider."
def add_arguments(self, parser):
parser.add_argument("username", help="account username")
parser.add_argument("password", help="account password")
parser.add_argument("email", help="account email address")
parser.add_argument("groups", help="account user groups", nargs='*')
def handle(self, **options):
username = options["username"]
password = options["password"]
email = options["email"]
groups = options["groups"]
if User.objects.filter(username=username).exists():
self.stdout.write("User {} already exists.".format(username))
return
user = User.objects.create(username=username, email=email)
user.set_password(password)
user.groups.set(groups)
user.save()
self.stdout.write("User {} created.".format(username))
"""
Django settings for oidcprovider project.
Generated by 'django-admin startproject' using Django 1.11.6.
For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '_brj&4ea0ec%ybc(rz32jpqwypdy4@d9lttg&g7!^e(m!-52si'
SESSION_COOKIE_NAME = 'oidcprovider'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ['*']
SITE_ID = 1
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
'oidc_provider',
'oidcprovider',
'pinax_theme_bootstrap',
'account',
'bootstrapform',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
# django-user-accounts
'account.middleware.LocaleMiddleware',
'account.middleware.TimezoneMiddleware'
]
ROOT_URLCONF = 'oidcprovider.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'pinax_theme_bootstrap.context_processors.theme',
'account.context_processors.account',
],
},
},
]
WSGI_APPLICATION = 'oidcprovider.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/
STATIC_URL = '/static/'
# OIDC provider settings
LOGIN_URL = '/account/login'
ACCOUNT_EMAIL_CONFIRMATION_EMAIL = False
# Workaround to actually delete the account instead of marking it as inactive
def _delete_user(obj):
obj.user.delete()
ACCOUNT_DELETION_MARK_CALLBACK = _delete_user
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment