Compare commits

...

2 Commits

4 changed files with 37 additions and 18 deletions

View File

@ -1 +1 @@
__version__ = '0.1.36' __version__ = '0.1.37'

View File

@ -1,6 +1,7 @@
from django.core.management.base import BaseCommand, CommandError from django.core.management.base import BaseCommand, CommandError
import datetime import datetime
import os.path import os.path
import sys
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives import hashes, serialization
@ -18,29 +19,45 @@ class Command(BaseCommand):
'them to the django settings.' 'them to the django settings.'
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument('--country', required=True, nargs=1, type=str, dest='country', help='For example: US, NL, DE, etc') parser.add_argument('--country', required=False, nargs='?', type=str, default=['NL'], dest='country', help='For example: US, NL, DE, etc')
parser.add_argument('--city', required=True, nargs=1, type=str, dest='city', help='For example: London or Groningen') parser.add_argument('--city', required=False, nargs='?', type=str, default=['Groningen'], dest='city', help='For example: London or Groningen')
parser.add_argument('--state', required=True, nargs=1, type=str, dest='state', help='For example: State or province, for example California or Groningen.') parser.add_argument('--state', required=False, nargs='?', type=str, default=['Groningen'], dest='state', help='For example: State or province, for example California or Groningen.')
parser.add_argument('--organisation', required=True, nargs=1, type=str, dest='organisation', help='Typically \'University of Groningen\'') parser.add_argument('--organisation', required=False, nargs='?', type=str, default=['University of Groningen'], dest='organisation', help='Typically \'University of Groningen\'')
parser.add_argument('--organisation-unit', required=True, nargs=1, type=str, dest='organisation_unit', help='For example: \'Research and Innovation\' Support or \'Faculty of smart people\'') parser.add_argument('--organisation-unit', required=True, nargs=1, type=str, dest='organisation_unit', help='For example: \'Research and Innovation\' Support or \'Faculty of smart people\'')
parser.add_argument('--common-name', required=True, nargs=1, type=str, dest='common_name') parser.add_argument('--common-name', required=True, nargs=1, type=str, dest='common_name')
parser.add_argument('--alternative', nargs='*', type=str, dest='alternatives') parser.add_argument('--alternative', nargs='*', type=str, dest='alternatives')
parser.add_argument('--support-name', required=True, nargs=1, type=str, dest='support_name') parser.add_argument('--support-name', required=True, nargs=1, type=str, dest='support_name')
parser.add_argument('--support-email', required=True, nargs=1, type=str, dest='support_email') parser.add_argument('--support-email', required=True, nargs=1, type=str, dest='support_email')
parser.add_argument('--technical-name', required=True, nargs=1, type=str, dest='technical_name') parser.add_argument('--technical-name', required=True, nargs=1, type=str, dest='technical_name')
parser.add_argument('--saml-route', required=False, nargs='?', type=str, dest='saml_route', default='sso/saml2/')
parser.add_argument('--technical-email', required=True, nargs=1, type=str, dest='technical_email') parser.add_argument('--technical-email', required=True, nargs=1, type=str, dest='technical_email')
parser.add_argument('--entity-id', required=True, nargs=1, type=str, dest='entity_id', help='Used as an identifyer of your service, typically the url to your service: www.rug.nl/yourservice') parser.add_argument('--entity-id', required=False, nargs='?', type=str, dest='entity_id', help='Used as an identifyer of your service, typically the url to your service: www.rug.nl/yourservice')
parser.add_argument('--base-url', required=True, nargs=1, type=str, dest='base_url', help='The base url of your service, the route <base_url>sso/saml/ should exist.') parser.add_argument('--base-url', required=False, nargs='?', type=str, dest='base_url', help='The base url of your service, the route <base_url>sso/saml/ should exist.')
parser.add_argument('--expires-after-days', nargs='?', type=int, default=10 * 365, dest='expires') parser.add_argument('--expires-after-days', nargs='?', type=int, default=10 * 365, dest='expires')
def handle(self, *args, **options): def handle(self, *args, **options):
print(options, file=sys.stderr)
for option in {'country', 'city', 'state', 'organisation', 'organisation_unit', 'common_name', 'support_name', for option in {'country', 'city', 'state', 'organisation', 'organisation_unit', 'common_name', 'support_name',
'support_email', 'technical_name', 'technical_email', 'entity_id', 'base_url'}: 'support_email', 'technical_name', 'technical_email'}:
assert option in options and options[option] is not None and len(options[option]) == 1, "Expected one " \ assert option in options and options[option] is not None and len(options[option]) == 1, "Expected one " \
"value for option" \ "value for option" \
": " + option ": " + option
options[option] = options[option][0] options[option] = options[option][0]
if options['base_url'] is None:
options['base_url'] = 'https://{}/'.format(options['common_name'])
print("# NOTE: deduced --base-url from --common-name: {}".format(options['base_url']), file=sys.stderr)
print("# NOTE: deduced --base-url from --common-name: {}".format(options['base_url']))
else:
options['base_url'] = options['base_url'][0]
if options['entity_id'] is None:
options['entity_id'] = '{}{}{}metadata?provider=RuG'.format(options['base_url'], '' if options['base_url'].endswith('/') else '/', options['saml_route'])
print("# NOTE: deduced --entity-id from --base-url and --saml-route: {}".format(options['entity_id']), file=sys.stderr)
print("# NOTE: deduced --entity-id from --base-url and --saml-route: {}".format(options['entity_id']))
else:
options['entity_id'] = options['entity_id'][0]
key = rsa.generate_private_key(public_exponent=65537, key_size=2048, backend = default_backend()) key = rsa.generate_private_key(public_exponent=65537, key_size=2048, backend = default_backend())
subject = issuer = x509.Name([ subject = issuer = x509.Name([
x509.NameAttribute(NameOID.COUNTRY_NAME, options['country']), x509.NameAttribute(NameOID.COUNTRY_NAME, options['country']),

View File

@ -9,6 +9,7 @@ ENTITY_ID = '{entity_id}'
# Important to make sure redirects and such work properly # Important to make sure redirects and such work properly
BASE_URL = '{base_url}' BASE_URL = '{base_url}'
BASE_URL_SLASH = BASE_URL + ('' if BASE_URL.endwith('/') else '/')
# This support information is used for the SAML2 service provider contact information # This support information is used for the SAML2 service provider contact information
TECHNICAL_NAME = '{technical_name}' TECHNICAL_NAME = '{technical_name}'
@ -20,16 +21,17 @@ ORGANISATION = '{organisation}'
ORGANISATION_UNIT = '{organisation_unit}' ORGANISATION_UNIT = '{organisation_unit}'
SAML_ROUTE = BASE_URL + 'sso/saml/' SAML_ROUTE = '{saml_route}'
SAML_ROUTE_SLASH = SAML_ROUTE + ('' if SAML_ROUTE.endwith('/') else '/')
# redirection after successful SAML2 login # redirection after successful SAML2 login
SAML_REDIRECT = BASE_URL + '/' SAML_REDIRECT = BASE_URL_SLASH
# Mapping used to move the SAML2 attributes to the django-auth user database # Mapping used to move the SAML2 attributes to the django-auth user database
SAML_USERS_MAP = [{{ SAML_USERS_MAP = [{{
"RuG": {{ "RuG": {{
"email": dict(key="urn:mace:dir:attribute-def:mail", index=0), "email": dict(key="urn:mace:dir:attribute-def:mail", index=0),
"username": dict(key="urn:mace:dir:attribute-def:uid", index=0), "username": dict(key="urn:mace:dir:attribute-def:uid", index=0),
"first_name": dict(key="urn:mace:dir:attribute-def:gn", index=0), "first_name": dict(key="urn:mace:dir:attribute-def:givenName", index=0),
"last_name": dict(key="urn:mace:dir:attribute-def:sn", index=0), "last_name": dict(key="urn:mace:dir:attribute-def:sn", index=0),
}} }}
}}] }}]
@ -41,7 +43,7 @@ PRIVATE_KEY = """{private_key}"""
X509 = """{x509}""" X509 = """{x509}"""
# RuG metadata url, should not change unless you want another service provider. # RuG metadata url, should not change unless you want another service provider.
SAML_PROVIDER_METADATA_URL = 'https://tst-idp.id.rug.nl/nidp/saml2/metadata' SAML_PROVIDER_METADATA_URL = 'https://signon.rug.nl/nidp/saml2/metadata'
#Code to get the RuG identity provider certificate #Code to get the RuG identity provider certificate
import sys import sys
@ -73,11 +75,11 @@ SAML_PROVIDERS = [{{
"sp": {{ "sp": {{
"entityId": ENTITY_ID, "entityId": ENTITY_ID,
"assertionConsumerService": {{ "assertionConsumerService": {{
"url": BASE_URL + "/sso/saml/?provider=RuG&amp;acs", "url": BASE_URL_SLASH + SAML_ROUTE_SLASH + "?provider=RuG&amp;acs",
"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
}}, }},
"singleLogoutService": {{ "singleLogoutService": {{
"url": BASE_URL + "/sso/saml/?provider=RuG", "url": BASE_URL_SLASH + SAML_ROUTE_SLASH + "?provider=RuG",
"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
}}, }},
"NameIDFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", "NameIDFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified",
@ -85,13 +87,13 @@ SAML_PROVIDERS = [{{
"privateKey": PRIVATE_KEY, "privateKey": PRIVATE_KEY,
}}, }},
"idp": {{ "idp": {{
"entityId": "https://tst-idp.id.rug.nl/nidp/saml2/metadata", "entityId": "https://signon.rug.nl/nidp/saml2/metadata",
"singleSignOnService": {{ "singleSignOnService": {{
"url": "https://tst-idp.id.rug.nl/nidp/saml2/sso", "url": "https://signon.rug.nl/nidp/saml2/sso",
"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
}}, }},
"singleLogoutService": {{ "singleLogoutService": {{
"url": "https://tst-idp.id.rug.nl/nidp/saml2/spslo", "url": "https://signon.rug.nl/nidp/saml2/spslo",
"binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
}}, }},
"x509cert": RUG_PROVIDER_X509CERT, "x509cert": RUG_PROVIDER_X509CERT,
@ -100,7 +102,7 @@ SAML_PROVIDERS = [{{
"en-US": {{ "en-US": {{
"name": ORGANISATION, "name": ORGANISATION,
"displayname": ORGANISATION + " / " + ORGANISATION_UNIT, "displayname": ORGANISATION + " / " + ORGANISATION_UNIT,
"url": BASE_URL "url": BASE_URL_SLASH
}} }}
}}, }},
"contact_person": {{ "contact_person": {{