diff --git a/rugwebsite/__init__.py b/rugwebsite/__init__.py index 997791c..da9d669 100644 --- a/rugwebsite/__init__.py +++ b/rugwebsite/__init__.py @@ -1 +1 @@ -__version__ = '0.1.36' +__version__ = '0.1.37' diff --git a/rugwebsite/__pycache__/urls.cpython-35.pyc b/rugwebsite/__pycache__/urls.cpython-35.pyc index bb85c7c..8bedd09 100644 Binary files a/rugwebsite/__pycache__/urls.cpython-35.pyc and b/rugwebsite/__pycache__/urls.cpython-35.pyc differ diff --git a/rugwebsite/management/commands/init-saml2-settings.py b/rugwebsite/management/commands/init-saml2-settings.py index d1a8df3..97ad67a 100644 --- a/rugwebsite/management/commands/init-saml2-settings.py +++ b/rugwebsite/management/commands/init-saml2-settings.py @@ -1,6 +1,7 @@ from django.core.management.base import BaseCommand, CommandError import datetime import os.path +import sys from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives import hashes, serialization @@ -18,29 +19,45 @@ class Command(BaseCommand): 'them to the django settings.' 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('--city', required=True, nargs=1, type=str, 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('--organisation', required=True, nargs=1, type=str, dest='organisation', help='Typically \'University of Groningen\'') + 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=False, nargs='?', type=str, default=['Groningen'], dest='city', help='For example: London 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=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('--common-name', required=True, nargs=1, type=str, dest='common_name') 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-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('--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('--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('--base-url', required=True, nargs=1, type=str, dest='base_url', help='The base url of your service, the route sso/saml/ should exist.') + 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=False, nargs='?', type=str, dest='base_url', help='The base url of your service, the route sso/saml/ should exist.') parser.add_argument('--expires-after-days', nargs='?', type=int, default=10 * 365, dest='expires') def handle(self, *args, **options): + print(options, file=sys.stderr) 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 " \ "value for option" \ ": " + option 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()) subject = issuer = x509.Name([ x509.NameAttribute(NameOID.COUNTRY_NAME, options['country']), diff --git a/rugwebsite/management/commands/settings_template.py b/rugwebsite/management/commands/settings_template.py index bd9f1e6..f1af370 100644 --- a/rugwebsite/management/commands/settings_template.py +++ b/rugwebsite/management/commands/settings_template.py @@ -9,6 +9,7 @@ ENTITY_ID = '{entity_id}' # Important to make sure redirects and such work properly 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 TECHNICAL_NAME = '{technical_name}' @@ -20,16 +21,17 @@ ORGANISATION = '{organisation}' 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 -SAML_REDIRECT = BASE_URL + '/' +SAML_REDIRECT = BASE_URL_SLASH # Mapping used to move the SAML2 attributes to the django-auth user database SAML_USERS_MAP = [{{ "RuG": {{ "email": dict(key="urn:mace:dir:attribute-def:mail", 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), }} }}] @@ -41,7 +43,7 @@ PRIVATE_KEY = """{private_key}""" X509 = """{x509}""" # 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 import sys @@ -73,11 +75,11 @@ SAML_PROVIDERS = [{{ "sp": {{ "entityId": ENTITY_ID, "assertionConsumerService": {{ - "url": BASE_URL + "/sso/saml/?provider=RuG&acs", + "url": BASE_URL_SLASH + SAML_ROUTE_SLASH + "?provider=RuG&acs", "binding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" }}, "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" }}, "NameIDFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", @@ -85,13 +87,13 @@ SAML_PROVIDERS = [{{ "privateKey": PRIVATE_KEY, }}, "idp": {{ - "entityId": "https://tst-idp.id.rug.nl/nidp/saml2/metadata", + "entityId": "https://signon.rug.nl/nidp/saml2/metadata", "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" }}, "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" }}, "x509cert": RUG_PROVIDER_X509CERT, @@ -100,7 +102,7 @@ SAML_PROVIDERS = [{{ "en-US": {{ "name": ORGANISATION, "displayname": ORGANISATION + " / " + ORGANISATION_UNIT, - "url": BASE_URL + "url": BASE_URL_SLASH }} }}, "contact_person": {{