SAML 2.0 authentication¶
Attention
OpenID Connect Authentication is generally recommended over SAML2 due to the complexity of its configuration.
Canopy can act as a SAML 2.0 Service Provider (SP) and authenticate against any SAML 2.0 compatible Identity provider (IdP) as a SSO solution with just-in-time user creation. Additionally it can populate user fields and role assignments directly from SAML attributes.
SAML authentication related settings are configured
in /etc/canopy/canopy.ini
, /etc/canopy/saml/config.py
and a few
other related files as specified in /etc/canopy/saml/config.py.
Any
change to them requires Canopy to be restarted.
Important Information¶
Login can be SP initiated or IdP initiated.
Canopy’s SAML URLs:
Metadata URL → https://CANOPY_SERVER/saml2/metadata/
Assertion Consumer Service (ACS) → http://CANOPY_SERVER/saml2/acs/ (HTTP POST binding)
Optional logout service:
http://CANOPY_SERVER/saml2/ls/ (HTTP Redirect binding)
http://CANOPY_SERVER/saml2/ls/post/ (HTTP POST binding)
The IdP’s metadata should be stored under
/etc/canopy/saml/metadata.xml
NameID identifier must be sent by IdP. This should be the user’s email address and be typed as a Persistent NameID.
Canopy requires that the email field is mapped to a SAML attribute that contains the users email address and the name field is mapped to the user’s name/surname attribute.
SAML request/response signing/transport certificate/key (X509) must be configured in
/etc/canopy/saml/config.py
.If a SAML attribute map is required then
/etc/canopy/saml/attributemaps/basic.py
should be updated accordingly. Specifically the attribute name format should match what the IdP is emitting.Example config files are located under
/opt/checksec/canopy/sample_configs/saml/
Configuration¶
Example config files may be used as a starting point via the following steps:
mkdir /etc/canopy/saml
cp /opt/checksec/canopy/sample_configs/saml/config.py /etc/canopy/saml/
cp -a /opt/checksec/canopy/sample_configs/saml/attributemaps /etc/canopy/saml/
The following config options (with defaults) are valid inside
/etc/canopy/canopy.ini
:
SAML_ENABLE=true
SAML_ATTRIBUTE_MAPPING=email=email # This is the minimum required. Format is: user_field1=saml_attribute1,user_field2=saml_attribute2
SAML_SSO_NAME=Single Sign On # Name of SSO service to display on login page
LOG_LEVEL_SAML=DEBUG # *** Remove this line after SAML configuration is complete
Additionally a SAML specific config file is also required at
/etc/canopy/saml/config.py
Many of the fields will need updating, specifically URLs and file locations.
Attribute Mapping¶
If allow_unknown_attributes
is not set to True
in config.py
under the SAML_CONFIG
dictionary then all attributes used must be
configured under required_attributes
or optional_attributes
and
in the attribute maps (/etc/canopy/saml/samlattributemaps/basic.py
).
At the very least the email and name fields MUST be mapped to SAML attributes.
Role assignment¶
- There are two ways user roles can be assigned via SAML attributes:
Multi valued attribute that contains the complete role list (New in 3.2.1)
Attribute per role
Both approaches form part of the SAML_ATTRIBUTE_MAPPING setting and can be used in combination (must be in the above order).
Multi valued attribute (Canopy 3.2.1+)¶
User roles can be sent via a multi valued SAML2 attribute, the user’s roles will be reset to this list. If the complete list of user roles cannot be sent via a single multi valued attribute then per role attributes will be required, possibly in addition to this.
The multi valued roles attribute needs to be mapped to the set_roles field.
SAML_ATTRIBUTE_MAPPING=email=email,name=name,set_roles=saml_roles_attribute
Role name translation (Canopy 3.2.1+)¶
Since the role names may not always match what Canopy expects, one can translate role names being sent via a multi valued SAML attribute using the SSO_USER_ROLE_MAPPING setting in /etc/canopy/canopy.ini
The mapping is a comma delimited list of SAML Role Name = Canopy Role Name
SSO_USER_ROLE_MAPPING=SAMLRoleName=canopy_role_name1, SAMLRoleName2=canopy_role_name2
This setting will apply role translation to all SSO methods.
Supported Roles¶
- All builtin and custom roles are supported, the builtin list of roles is:
admin
technical-managers
senior-analysts
analysts
schedulers
sales-managers
account-managers
kb-admins
pr-reviewers
qa-reviewers
For custom roles their name in lower case will be used.
Attribute per role¶
Assigning roles based on SAML attributes is optional and not all flags need to be mapped. Unmapped flags can be managed via the Canopy admin interface. The attribute value should be any string value to signify membership, except for the following strings, which denote the removal of the role: ‘’ (Empty string), ‘no’, ‘false’ and ‘0’.
If the attribute is missing then no adjustment will occur.
- Role fields currently supported:
is_admin
is_technical_managers
is_senior_analysts
is_analysts
is_schedulers
is_sales_managers
is_account_managers
is_custom_pr_reviewers
is_custom_qa_reviewers
SAML_ATTRIBUTE_MAPPING=email=email, name=name, is_admin=saml_admin_attribute
if per attribute role mappings are in use with multi valued attribute role mapping then the role flags should be after the set_roles mapping.
SAML_ATTRIBUTE_MAPPING=email=email, name=name, set_roles=saml_roles_attribute, is_admin=saml_admin_attribute
Note
Per role attributes do not support custom roles.
Microsoft ADFS¶
ADFS requires some additional configuration:
A NameID claim with the correct name format is required. Most IdPs send these but ADFS doesn’t by default. See https://blogs.msdn.microsoft.com/card/2010/02/17/name-identifiers-in-saml-assertions/ If this is not sent then Canopy will error with AttributeError: ‘NoneType’ object has no attribute ‘name_qualifier’ in its logs.
When set to send a group membership claims, ADFS will not submit the claim when the user is NOT in the given group. Canopy will be unable to remove a role from a user. To correct this one requires an additional custom claim rule to submit the lack of membership to a group:
NOT EXISTS([Type == "GROUPCLAIMTYPE"]) => issue(Type = "GROUPCLAIMTYPE", Value = "");
Note
This is however not required when using the multi valued attribute approach as it resets the roles list.
Multi valued attribute for Canopy role claims¶
An efficient approach to provisioning user roles from ADFS groups is to use a consistent naming convention for the ADFS groups that contain the Canopy role names, combined with claim issuance transformation rules to emit the Canopy roles.
For example, the if the naming convention for Canopy roles as ADFS groups were PREFIX-Canopy-ENVIRONMENT-CANOPYROLE
- then Canopy roles can be mapped using ADFS group names such as:
Application-Canopy-PROD-admin
Application-Canopy-PROD-analysts
Application-Canopy-PROD-senior_analysts
Application-Canopy-PROD-customrole1
The custom claim issuance transformation rules required to convert these group names into Canopy roles are as follows:
c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
=> add(store = "Active Directory", types = ("canopyroles"), query = ";tokenGroups;{0}", param = c.Value);
This adds a claim named canopyroles with ALL of the user’s ADFS groups
c:[Type == "canopyroles", Value =~ "^Application-Canopy"]
=> issue(Type = "canopyroles", Value = RegExReplace(c.Value, "^.*-PROD-", ""));
then the 2nd rule filters the groups to the relevant ones, strips everything that isn’t part of the Canopy Role and issues the claim.
For the above example the appropriate setting in /etc/canopy/canopy.ini would be similar to (note the set_roles=canopyroles part):
SAML_ATTRIBUTE_MAPPING=name=uid,email=email,set_roles=canopyroles