Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: replace django-saml2-auth with djangosaml2 #4117

Merged
merged 13 commits into from
Jun 26, 2021
Merged
12 changes: 12 additions & 0 deletions docs/content/en/getting_started/upgrading.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ Replace the first step above with this one: `docker-compose build`

Follow the usual steps to upgrade as described above.

BEFORE UPGRADING
- If you are using SAML2 checkout the new [documentaion](https://defectdojo.github.io/django-DefectDojo/integrations/social-authentication/#saml-20) and update you settings following the migration section. We replaced [django-saml2-auth](https://github.com/fangli/django-saml2-auth) with [djangosaml2](https://github.com/IdentityPython/djangosaml2).

AFTER UPGRADING
- Usual migration process (`python manage.py migrate`) try to migrate all endpoints to new format and merge duplicates.
- All broken endpoints (which weren't possible to migrate) have red flag 🚩 in standard list of endpoints.
- Check if all your endpoints was migrated successfully, go to: https://<defect-dojo-url>/endpoint/migrate.
- Alternatively, this can be run as management command: `docker-compose exec uwsgi ./manage.py endpoint_migration --dry-run`
- When all endpoint will be fixed (there is not broken endpoint), press "Run migration" in https://<defect-dojo-url>/endpoint/migrate
- Or, you can run management command: `docker-compose exec uwsgi ./manage.py endpoint_migration`
- Details about endpoint migration / improvements in https://github.com/DefectDojo/django-DefectDojo/pull/4473

We decided to name this version 2.0.0 because we did some big cleanups in this release:

- Remove API v1 ([#4413](https://github.com/DefectDojo/django-DefectDojo/pull/4413))
Expand Down
61 changes: 41 additions & 20 deletions docs/content/en/integrations/social-authentication.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: "Authentication via OAuth2"
description: "OAuth2 let users authenticate against enterprise directories."
title: "Authentication via OAuth2/SAML2"
description: "OAuth2/SAML2 let users authenticate against enterprise directories."
draft: false
weight: 3
---
Expand Down Expand Up @@ -234,39 +234,32 @@ Follow along below.
button on the login page.

## SAML 2.0

{{% alert title="Warning" color="warning" %}}
The SAML integration below is based on [https://github.com/fangli/django-saml2-auth](django-saml2-auth) which is no longer maintained, see #3890
{{% /alert %}}

In a similar direction to OAuth, this SAML addition provides a more secure
perogative to SSO. For definitions of terms used and more information,
see the plugin [plugin
homepage](https://github.com/fangli/django-saml2-auth)
homepage](https://github.com/IdentityPython/djangosaml2).

1. Navigate to your SAML IdP and find your metadata
2. Edit the dojo/`dojo/settings/settings.dist.py` file:
2. Edit the dojo/`dojo/settings/settings.dist.py` file or set the corresponding environment variables:

{{< highlight python >}}
DD_SAML2_ENABLED=(bool, **True**),
# If the metadata can be accessed from a url, try the
DD_SAML2_METADATA_AUTO_CONF_URL
DD_SAML2_METADATA_AUTO_CONF_URL=(str, '<https://your_IdP.com/metadata.xml>'),
# Otherwise, downlaod a copy of the metadata into an xml file, and
# list the path in DD_SAML2_METADATA_LOCAL_FILE_PATH
DD_SAML2_METADATA_LOCAL_FILE_PATH=(str, '/path/to/your/metadata.xml'),
# Fill in DD_SAML2_ASSERTION_URL and DD_SAML2_ENTITY_ID to
# match the specs of you IdP.
# Configure the remaining optional fields to your desire.
# Fill in DD_SAML2_ATTRIBUTES_MAP to corresponding SAML2 userprofile attributes provided by your IdP
DD_SAML2_ATTRIBUTES_MAP=(dict, {
'Email': ('email', ),
'Firstname': ('first_name', ),
'Lastname': ('last_name', )
}),
# May configure the optional fields
{{< /highlight >}}

4. In the "Authentication" section of the `dojo/settings/settings.dist.py`, do the
following

- Find the "SAML_2_AUTH" dictionary
- Comment out the metadata collection method that was not used.
- For example, if METADATA_AUTO_CONF_URL was used, comment the
METADATA_LOCAL_FILE_PATH line.
4. Checkout the SAML section in dojo/`dojo/settings/settings.dist.py` and verfiy if it fits your requirement. If you need help, take a look at the [plugin
documentation](https://djangosaml2.readthedocs.io/contents/setup.html#configuration).

5. Restart DefectDojo, and you should now see a **Login with SAML**
button on the login page.
Expand All @@ -275,6 +268,34 @@ NOTE: In the case when IDP is configured to use self signed certificate,
than CA needs to be specified by define environments variable
REQUESTS_CA_BUNDLE that points to the path of public CA certificate.

### Advanced Configuration
The [https://github.com/IdentityPython/djangosaml2](djangosaml2) plugin has a lot of options. For details take a look at the [plugin
documentation](https://djangosaml2.readthedocs.io/contents/setup.html#configuration). All default options in DefectDojo can overwritten in the local_settings.py. If you want to change the organization name, you can add the following lines:

{{< highlight python >}}
if SAML2_ENABLED:
SAML_CONFIG['contact_person'] = [{
'given_name': 'Extra',
'sur_name': 'Example',
'company': 'DefectDojo',
'email_address': '[email protected]',
'contact_type': 'technical'
}]
SAML_CONFIG['organization'] = {
'name': [('DefectDojo', 'en')],
'display_name': [('DefectDojo', 'en')],
},
{{< /highlight >}}

### Migration from django-saml2-auth
Up to relase 1.15.0 the SAML integration was based on [https://github.com/fangli/django-saml2-auth](django-saml2-auth). Which the switch to djangosaml2 some parameters has changed:

* DD_SAML2_ASSERTION_URL: not necessary any more - automatically generated
* DD_SAML2_DEFAULT_NEXT_URL: not necessary any more - default forwarding from defectdojo is used
* DD_SAML2_NEW_USER_PROFILE: not possible any more - default profile is used, see User Permissions
* DD_SAML2_ATTRIBUTES_MAP: Syntax has changed
* DD_SAML2_CREATE_USER: Default value changed to False, to avoid security breaches

## User Permissions

When a new user is created via the social-auth, only the default permissions are active. This means that the newly created user does not have access to add, edit, nor delete anything within DefectDojo. To circumvent that, a custom pipeline was added (dojo/pipline.py/modify_permissions) to elevate new users to staff. This can be disabled by setting 'is_staff' equal to False. Similarly, for an admin account, simply add the following to the modify_permissions pipeline:
Expand Down
19 changes: 19 additions & 0 deletions dojo/settings/attribute-maps/django_saml_uri.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
X500ATTR_OID = 'urn:oid:2.5.4.'
PKCS_9 = 'urn:oid:1.2.840.113549.1.9.1.'
UCL_DIR_PILOT = 'urn:oid:0.9.2342.19200300.100.1.'

MAP = {
'identifier': 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
'fro': {
X500ATTR_OID + '3': 'first_name', # cn
X500ATTR_OID + '4': 'last_name', # sn
PKCS_9 + '1': 'email',
UCL_DIR_PILOT + '1': 'uid',
},
'to': {
'first_name': X500ATTR_OID + '3',
'last_name': X500ATTR_OID + '4',
'email': PKCS_9 + '1',
'uid': UCL_DIR_PILOT + '1',
}
}
243 changes: 243 additions & 0 deletions dojo/settings/attribute-maps/saml_uri.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
__author__ = 'rolandh'

EDUPERSON_OID = "urn:oid:1.3.6.1.4.1.5923.1.1.1."
X500ATTR_OID = "urn:oid:2.5.4."
NOREDUPERSON_OID = "urn:oid:1.3.6.1.4.1.2428.90.1."
NETSCAPE_LDAP = "urn:oid:2.16.840.1.113730.3.1."
UCL_DIR_PILOT = 'urn:oid:0.9.2342.19200300.100.1.'
PKCS_9 = "urn:oid:1.2.840.113549.1.9.1."
UMICH = "urn:oid:1.3.6.1.4.1.250.1.57."
SCHAC = "urn:oid:1.3.6.1.4.1.25178.1.2."

MAP = {
"identifier": "urn:oasis:names:tc:SAML:2.0:attrname-format:uri",
"fro": {
EDUPERSON_OID + '2': 'eduPersonNickname',
EDUPERSON_OID + '9': 'eduPersonScopedAffiliation',
EDUPERSON_OID + '11': 'eduPersonAssurance',
EDUPERSON_OID + '10': 'eduPersonTargetedID',
EDUPERSON_OID + '4': 'eduPersonOrgUnitDN',
NOREDUPERSON_OID + '6': 'norEduOrgAcronym',
NOREDUPERSON_OID + '7': 'norEduOrgUniqueIdentifier',
NOREDUPERSON_OID + '4': 'norEduPersonLIN',
EDUPERSON_OID + '1': 'eduPersonAffiliation',
NOREDUPERSON_OID + '2': 'norEduOrgUnitUniqueNumber',
NETSCAPE_LDAP + '40': 'userSMIMECertificate',
NOREDUPERSON_OID + '1': 'norEduOrgUniqueNumber',
NETSCAPE_LDAP + '241': 'displayName',
UCL_DIR_PILOT + '37': 'associatedDomain',
EDUPERSON_OID + '6': 'eduPersonPrincipalName',
NOREDUPERSON_OID + '8': 'norEduOrgUnitUniqueIdentifier',
NOREDUPERSON_OID + '9': 'federationFeideSchemaVersion',
X500ATTR_OID + '53': 'deltaRevocationList',
X500ATTR_OID + '52': 'supportedAlgorithms',
X500ATTR_OID + '51': 'houseIdentifier',
X500ATTR_OID + '50': 'uniqueMember',
X500ATTR_OID + '19': 'physicalDeliveryOfficeName',
X500ATTR_OID + '18': 'postOfficeBox',
X500ATTR_OID + '17': 'postalCode',
X500ATTR_OID + '16': 'postalAddress',
X500ATTR_OID + '15': 'businessCategory',
X500ATTR_OID + '14': 'searchGuide',
EDUPERSON_OID + '5': 'eduPersonPrimaryAffiliation',
X500ATTR_OID + '12': 'title',
X500ATTR_OID + '11': 'ou',
X500ATTR_OID + '10': 'o',
X500ATTR_OID + '37': 'cACertificate',
X500ATTR_OID + '36': 'userCertificate',
X500ATTR_OID + '31': 'member',
X500ATTR_OID + '30': 'supportedApplicationContext',
X500ATTR_OID + '33': 'roleOccupant',
X500ATTR_OID + '32': 'owner',
NETSCAPE_LDAP + '1': 'carLicense',
PKCS_9 + '1': 'email',
NETSCAPE_LDAP + '3': 'employeeNumber',
NETSCAPE_LDAP + '2': 'departmentNumber',
X500ATTR_OID + '39': 'certificateRevocationList',
X500ATTR_OID + '38': 'authorityRevocationList',
NETSCAPE_LDAP + '216': 'userPKCS12',
EDUPERSON_OID + '8': 'eduPersonPrimaryOrgUnitDN',
X500ATTR_OID + '9': 'street',
X500ATTR_OID + '8': 'st',
NETSCAPE_LDAP + '39': 'preferredLanguage',
EDUPERSON_OID + '7': 'eduPersonEntitlement',
X500ATTR_OID + '2': 'knowledgeInformation',
X500ATTR_OID + '7': 'l',
X500ATTR_OID + '6': 'c',
X500ATTR_OID + '5': 'serialNumber',
X500ATTR_OID + '4': 'sn',
X500ATTR_OID + '3': 'cn',
UCL_DIR_PILOT + '60': 'jpegPhoto',
X500ATTR_OID + '65': 'pseudonym',
NOREDUPERSON_OID + '5': 'norEduPersonNIN',
UCL_DIR_PILOT + '3': 'mail',
UCL_DIR_PILOT + '25': 'dc',
X500ATTR_OID + '40': 'crossCertificatePair',
X500ATTR_OID + '42': 'givenName',
X500ATTR_OID + '43': 'initials',
X500ATTR_OID + '44': 'generationQualifier',
X500ATTR_OID + '45': 'x500UniqueIdentifier',
X500ATTR_OID + '46': 'dnQualifier',
X500ATTR_OID + '47': 'enhancedSearchGuide',
X500ATTR_OID + '48': 'protocolInformation',
X500ATTR_OID + '54': 'dmdName',
NETSCAPE_LDAP + '4': 'employeeType',
X500ATTR_OID + '22': 'teletexTerminalIdentifier',
X500ATTR_OID + '23': 'facsimileTelephoneNumber',
X500ATTR_OID + '20': 'telephoneNumber',
X500ATTR_OID + '21': 'telexNumber',
X500ATTR_OID + '26': 'registeredAddress',
X500ATTR_OID + '27': 'destinationIndicator',
X500ATTR_OID + '24': 'x121Address',
X500ATTR_OID + '25': 'internationaliSDNNumber',
X500ATTR_OID + '28': 'preferredDeliveryMethod',
X500ATTR_OID + '29': 'presentationAddress',
EDUPERSON_OID + '3': 'eduPersonOrgDN',
NOREDUPERSON_OID + '3': 'norEduPersonBirthDate',
UMICH + '57': 'labeledURI',
UCL_DIR_PILOT + '1': 'uid',
SCHAC + '1': 'schacMotherTongue',
SCHAC + '2': 'schacGender',
SCHAC + '3': 'schacDateOfBirth',
SCHAC + '4': 'schacPlaceOfBirth',
SCHAC + '5': 'schacCountryOfCitizenship',
SCHAC + '6': 'schacSn1',
SCHAC + '7': 'schacSn2',
SCHAC + '8': 'schacPersonalTitle',
SCHAC + '9': 'schacHomeOrganization',
SCHAC + '10': 'schacHomeOrganizationType',
SCHAC + '11': 'schacCountryOfResidence',
SCHAC + '12': 'schacUserPresenceID',
SCHAC + '13': 'schacPersonalPosition',
SCHAC + '14': 'schacPersonalUniqueCode',
SCHAC + '15': 'schacPersonalUniqueID',
SCHAC + '17': 'schacExpiryDate',
SCHAC + '18': 'schacUserPrivateAttribute',
SCHAC + '19': 'schacUserStatus',
SCHAC + '20': 'schacProjectMembership',
SCHAC + '21': 'schacProjectSpecificRole',
},
"to": {
'roleOccupant': X500ATTR_OID + '33',
'gn': X500ATTR_OID + '42',
'norEduPersonNIN': NOREDUPERSON_OID + '5',
'title': X500ATTR_OID + '12',
'facsimileTelephoneNumber': X500ATTR_OID + '23',
'mail': UCL_DIR_PILOT + '3',
'postOfficeBox': X500ATTR_OID + '18',
'fax': X500ATTR_OID + '23',
'telephoneNumber': X500ATTR_OID + '20',
'norEduPersonBirthDate': NOREDUPERSON_OID + '3',
'rfc822Mailbox': UCL_DIR_PILOT + '3',
'dc': UCL_DIR_PILOT + '25',
'countryName': X500ATTR_OID + '6',
'emailAddress': PKCS_9 + '1',
'employeeNumber': NETSCAPE_LDAP + '3',
'organizationName': X500ATTR_OID + '10',
'eduPersonAssurance': EDUPERSON_OID + '11',
'norEduOrgAcronym': NOREDUPERSON_OID + '6',
'registeredAddress': X500ATTR_OID + '26',
'physicalDeliveryOfficeName': X500ATTR_OID + '19',
'associatedDomain': UCL_DIR_PILOT + '37',
'l': X500ATTR_OID + '7',
'stateOrProvinceName': X500ATTR_OID + '8',
'federationFeideSchemaVersion': NOREDUPERSON_OID + '9',
'pkcs9email': PKCS_9 + '1',
'givenName': X500ATTR_OID + '42',
'givenname': X500ATTR_OID + '42',
'x500UniqueIdentifier': X500ATTR_OID + '45',
'eduPersonNickname': EDUPERSON_OID + '2',
'houseIdentifier': X500ATTR_OID + '51',
'street': X500ATTR_OID + '9',
'supportedAlgorithms': X500ATTR_OID + '52',
'preferredLanguage': NETSCAPE_LDAP + '39',
'postalAddress': X500ATTR_OID + '16',
'email': PKCS_9 + '1',
'norEduOrgUnitUniqueIdentifier': NOREDUPERSON_OID + '8',
'eduPersonPrimaryOrgUnitDN': EDUPERSON_OID + '8',
'c': X500ATTR_OID + '6',
'teletexTerminalIdentifier': X500ATTR_OID + '22',
'o': X500ATTR_OID + '10',
'cACertificate': X500ATTR_OID + '37',
'telexNumber': X500ATTR_OID + '21',
'ou': X500ATTR_OID + '11',
'initials': X500ATTR_OID + '43',
'eduPersonOrgUnitDN': EDUPERSON_OID + '4',
'deltaRevocationList': X500ATTR_OID + '53',
'norEduPersonLIN': NOREDUPERSON_OID + '4',
'supportedApplicationContext': X500ATTR_OID + '30',
'eduPersonEntitlement': EDUPERSON_OID + '7',
'generationQualifier': X500ATTR_OID + '44',
'eduPersonAffiliation': EDUPERSON_OID + '1',
'edupersonaffiliation': EDUPERSON_OID + '1',
'eduPersonPrincipalName': EDUPERSON_OID + '6',
'edupersonprincipalname': EDUPERSON_OID + '6',
'localityName': X500ATTR_OID + '7',
'owner': X500ATTR_OID + '32',
'norEduOrgUnitUniqueNumber': NOREDUPERSON_OID + '2',
'searchGuide': X500ATTR_OID + '14',
'certificateRevocationList': X500ATTR_OID + '39',
'organizationalUnitName': X500ATTR_OID + '11',
'userCertificate': X500ATTR_OID + '36',
'preferredDeliveryMethod': X500ATTR_OID + '28',
'internationaliSDNNumber': X500ATTR_OID + '25',
'uniqueMember': X500ATTR_OID + '50',
'departmentNumber': NETSCAPE_LDAP + '2',
'enhancedSearchGuide': X500ATTR_OID + '47',
'userPKCS12': NETSCAPE_LDAP + '216',
'eduPersonTargetedID': EDUPERSON_OID + '10',
'norEduOrgUniqueNumber': NOREDUPERSON_OID + '1',
'x121Address': X500ATTR_OID + '24',
'destinationIndicator': X500ATTR_OID + '27',
'eduPersonPrimaryAffiliation': EDUPERSON_OID + '5',
'surname': X500ATTR_OID + '4',
'jpegPhoto': UCL_DIR_PILOT + '60',
'eduPersonScopedAffiliation': EDUPERSON_OID + '9',
'edupersonscopedaffiliation': EDUPERSON_OID + '9',
'protocolInformation': X500ATTR_OID + '48',
'knowledgeInformation': X500ATTR_OID + '2',
'employeeType': NETSCAPE_LDAP + '4',
'userSMIMECertificate': NETSCAPE_LDAP + '40',
'member': X500ATTR_OID + '31',
'streetAddress': X500ATTR_OID + '9',
'dmdName': X500ATTR_OID + '54',
'postalCode': X500ATTR_OID + '17',
'pseudonym': X500ATTR_OID + '65',
'dnQualifier': X500ATTR_OID + '46',
'crossCertificatePair': X500ATTR_OID + '40',
'eduPersonOrgDN': EDUPERSON_OID + '3',
'authorityRevocationList': X500ATTR_OID + '38',
'displayName': NETSCAPE_LDAP + '241',
'businessCategory': X500ATTR_OID + '15',
'serialNumber': X500ATTR_OID + '5',
'norEduOrgUniqueIdentifier': NOREDUPERSON_OID + '7',
'st': X500ATTR_OID + '8',
'carLicense': NETSCAPE_LDAP + '1',
'presentationAddress': X500ATTR_OID + '29',
'sn': X500ATTR_OID + '4',
'cn': X500ATTR_OID + '3',
'domainComponent': UCL_DIR_PILOT + '25',
'labeledURI': UMICH + '57',
'uid': UCL_DIR_PILOT + '1',
'schacMotherTongue': SCHAC + '1',
'schacGender': SCHAC + '2',
'schacDateOfBirth': SCHAC + '3',
'schacPlaceOfBirth': SCHAC + '4',
'schacCountryOfCitizenship': SCHAC + '5',
'schacSn1': SCHAC + '6',
'schacSn2': SCHAC + '7',
'schacPersonalTitle': SCHAC + '8',
'schacHomeOrganization': SCHAC + '9',
'schacHomeOrganizationType': SCHAC + '10',
'schacCountryOfResidence': SCHAC + '11',
'schacUserPresenceID': SCHAC + '12',
'schacPersonalPosition': SCHAC + '13',
'schacPersonalUniqueCode': SCHAC + '14',
'schacPersonalUniqueID': SCHAC + '15',
'schacExpiryDate': SCHAC + '17',
'schacUserPrivateAttribute': SCHAC + '18',
'schacUserStatus': SCHAC + '19',
'schacProjectMembership': SCHAC + '20',
'schacProjectSpecificRole': SCHAC + '21',
}
}
Loading