Skip to content

Commit

Permalink
Merge pull request #118 from humanmade/backport-115-to-v14-branch
Browse files Browse the repository at this point in the history
[Backport v14-branch] Embetter SAML docs
  • Loading branch information
kovshenin authored Feb 27, 2023
2 parents 97e74f0 + 8234445 commit 22087cf
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 0 deletions.
File renamed without changes.
91 changes: 91 additions & 0 deletions docs/saml-2-0/mapping.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Mapping Data

The SAML SSO functionality includes out-of-the-box functionality for mapping data from your identity provider (IdP) to WordPress-native data.

This mapping can be customized and extended to match the way your IdP stores data.


## User details

By default, the following fields are mapped:

* `user_login` field (equivalent to a user slug): `email` SAML attribute
* `user_email`: `email` SAML attribute
* `first_name`: `firstName` SAML attribute
* `last_name`: `lastName` SAML attribute

This can be filtered via the `wpsimplesaml_attribute_mapping` filter, which receives an associative array mapping user properties to SAML attribute name. (Note: only these four fields are supported.)

For example, for Active Directory (AD), you may want to use the [AD claims](https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/technical-reference/the-role-of-claims) instead:

```php
add_filter( 'wpsimplesaml_attribute_mapping', function() {
return [
'user_email' => 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress',
'first_name' => 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname',
'last_name' => 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname',
'user_login' => 'http://schemas.microsoft.com/identity/claims/displayname',
];
} );
```

### Advanced user details

Aside from the direct mapping of these, you can also filter the final data before it is sent to WordPress, via the `wpsimplesaml_user_data` filter.

This filter receives the full user data being passed to `wp_insert_user`. You can use it to apply any other customization (including adding metadata) to this user data. You'll also receive the SAML attributes.

```
/**
* Filters user data before insertion to the database
*
* @param array $user_data User data being passed to wp_insert_user()
* @param array $attributes Attributes array coming from SAML Response object
*/
apply_filters( 'wpsimplesaml_user_data', $user_data, $attributes );
```


## Unique user matching

By default, when SAML SSO attempts to find an existing user, it'll look for any user with a matching email address (as returned from your mapping code). You may want to change this to deduplicate based on other user data instead.

The `wpsimplesaml_match_user` filter allows you to implement your own user matching code:

```php
/**
* Filters matched user, allows matching via other SAML attributes
*
* @param null|false|\WP_User $user User object or false if not found
* @param string $email Email from SAMLResponse
* @param array $attributes SAML Attributes parsed from SAMLResponse
*/
$user = apply_filters( 'wpsimplesaml_match_user', null, $email, $attributes );
```

For example, if you have multiple corporate domains and need to deduplicate them:

```php
// Treat all users from corporate domains as equal.
add_filter( 'wpsimplesaml_match_user', function ( $user, $email ) {
$email_parts = explode( '@', $email );
$domains = [
'example.com',
'example.org',
'example.net',
];
foreach ( $aliases as $alias ) {
$aliased_user = get_user_by( 'email', $email_parts[0] . '@' . $alias );
if ( $aliased_user ) {
return $aliased_user;
}
}

return $user;
}, 10, 2 );
```


## Role mapping

Roles can also be mapped; see the [user roles](./roles.md) documentation for more details.
114 changes: 114 additions & 0 deletions docs/saml-2-0/roles.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# User Roles

SAML SSO contains default functionality to handle roles for users created via SSO, but in many cases you may want more complex behaviour.

A variety of filters are provided to help map the data across from your identity provider (IdP).


## Automatic default role

By default, when users log in, they'll receive the default role for your site, matching WordPress' behaviour for open registration sites. (Typically, this is `subscriber`.)

For large multisites or complex use cases, this may not be desirable, as you may want to assign roles manually instead. This setting can be changed by returning false from the `wpsimplesaml_add_users_to_site` filter.

```php
add_filter( 'wpsimplesaml_add_users_to_site', '__return_false' );
```

This filter receives the enabled boolean as the filterable value, and additionally receives the `WP_User` object as the second parameter, allowing you to change behaviour based on the specific user.


## Mapping roles from your IdP

By default, roles aren't synchronized from your IdP, allowing you to manually assign them in WordPress instead.

In cases where you want to synchronize these roles, you can use the `wpsimplesaml_map_role` filter to determine the user's role. This could be hardcoded, or use information from your IdP such as the ActiveDirectory role claim.

The `wpsimplesaml_map_role` filter receives the following parameters:

```php
/**
* Filter the role to apply for the new user
*
* Example for single sites:
* [ 'editor', 'job_admin' ]
* 'administrator'
*
* Examples for multisite networks:
*
* - To apply a role for all sites in the network
* [ 'network' => [ 'administrator' ] ]
* 'administrator'
*
* - To grant network superadmin role
* [ 'network' => [ 'superadmin' ] ]
* 'superadmin'
*
* - To choose specific roles for each site ( user will be removed from omitted sites )
* [ 'sites' => [ 1 => [ 'administrator' ], 2 => [ 'editor' ] ]
*
* @param array $attributes SAML attributes
* @param int $user_id User ID
* @param \WP_User $user User object
*
* @return string|array WP Role(s) to apply to the user
*/
apply_filters( 'wpsimplesaml_map_role', get_option( 'default_role' ), $attributes, $user->ID, $user );
```

You'll also need to enable mapping via the `wpsimplesaml_manage_roles` filter:

```php
add_filter( 'wpsimplesaml_manage_roles', '__return_true', 11 );
```

For example, you could hardcode this to make all users editors instead of the default role:

```php
add_filter( 'wpsimplesaml_manage_roles', '__return_true', 11 );
add_filter( 'wpsimplesaml_map_role', function ( $role ) {
return [
'editor',
];
} );
```


### Mapping from Active Directory role claim

When connecting to an Active Directory (AD) SAML IdP, you may wish to use roles stored in the IdP.

These are exposed via the `http://schemas.microsoft.com/ws/2008/06/identity/claims/role` claim in SAML, and can be mapped from the SAML attributes in your custom code.

```php
// Map AD user group membership to WordPress roles.
add_filter( 'wpsimplesaml_map_role', __NAMESPACE__ . '\\map_user_role', 10, 2 );
add_filter( 'wpsimplesaml_manage_roles', '__return_true', 11 );

/**
* Map Active Directory user group membership to WordPress roles.
*
* @param string|array $default_role Default user role.
* @param array $attributes SAML attributes.
*
* @return string|array Updated user role.
*/
function map_user_role( $default_role, array $attributes ) {
$role_key = 'http://schemas.microsoft.com/ws/2008/06/identity/claims/role';

switch ( $attributes[ $role_key ][0] ?? null ) {
case 'gg_rol_EX-PROD-Admins':
return 'administrator';

case 'gg_rol_EX-PROD-Editors':
return 'editor';

case 'gg_rol_EX-PROD-ReadOnly':
return 'subscriber';

default:
// Give no roles by default.
return [];
}
}
```

0 comments on commit 22087cf

Please sign in to comment.