Canopy
Canopy

SAML 2.0 authentication

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:

  • The IdP’s metadata should be stored under /etc/canopy/saml/metadata.xml and IdP’s metadata URL must be configured in /etc/canopy/saml/config.py

  • 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/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/configs/saml/config.py /etc/canopy/saml/
cp -a /opt/checksec/canopy/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

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_MAP=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
  • pr_reviewers
  • qa_reviewers

For custom roles their name will be used which is case sensitive.

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. To unset/remove a role the SAML attribute should be have an value of “” (an empty string). Any other value will indicate the role is present. 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_MAP=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_MAP=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/

  • 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