Configuring Shiny Server Pro with LDAP or Active Directory

Follow

Introduction

The Shiny Server Admin Guide provides detailed information about all configuration directives that could be used to configure your Shiny Server Pro for LDAP and/or Active Directory authentication. 

In this document we provide some examples that could be used as a starting point.  Additional examples can be found in the LDAP example article

We strongly recommend that before you start configuring for LDAP/AD, first enable TRACE logging on the server. For instructions on how to modify logging level refer to this section of the Admin Guide.

 

Basic LDAP Configuration

For some LDAP structures a very simple configuration listed below will work:

auth_ldap ldap://localhost/dc=company,dc=com {
}

This configuration uses the default bind template of: uid={username},ou=People,{root} to bind the user. With this configuration, a user logging in as "myname" will see the following in the shiny-server.log:

[TRACE] shiny-server - Attempting to bind LDAP user 'uid=myname,ou=People,dc=company,dc=com

And this works as long as user's DN in the LDAP matches that string.

But in most cases the format of the user's DN is different than the default, and you would need to define that as in the following example where users belong to ou=Corporate:

auth_ldap ldap://localhost/dc=company,dc=com {
user_bind_template "cn={username},ou=Corporate,{root}";
}


With this configuration, user logging in as "myname" will see the following in the shiny-server.log:

[TRACE] shiny-server - Attempting to bind LDAP user 'cn=myname,ou=Corporate,dc=company,dc=com'

 

LDAP and Groups:

Shiny Server Pro provides the option to authorize access to the Admin console and/or your Shiny applications based on group membership. Here is an example that uses group_filter directive to find groups based on user's DN and group member attribute:

auth_ldap ldap://localhost/dc=company,dc=com {
group_filter "member={userDN}";
user_bind_template "cn={username},ou=People,{root}";
}

User logging in as "myname" will see the following in the shiny-server.log:

[TRACE] shiny-server - Attempting to bind LDAP user 'cn=myname,ou=People,dc=company,dc=com
...
[TRACE] shiny-server - Retrieving groups for user 'cn=username,ou=People,dc=company,dc=com' using filter: '(member=cn=username,ou=People,dc=company,dc=com)' in 'ou=Groups,dc=company,dc=com'
[TRACE] shiny-server - Discovered groups: Administrators

As you can see in the last line, one or more groups were found for this user, and therefore group-based authorization would work for this user.

If you do not define group_filter, Shiny Server by default uses uniqueMember={username} as the filter, and searches in ou=Groups, as the following log message shows:

[TRACE] shiny-server - Retrieving groups for user 'cn=myname,ou=People,dc=company,dc=com' using filter: '(uniqueMember=myname)' in 'ou=Groups,dc=company,dc=com

Most likely your LDAP structure has a different groups root than ou=Groups. You can configure that using group_search_base directive as in the following example:

auth_ldap ldap://localhost/dc=company,dc=com {
group_filter "member={userDN}";
group_search_base ou=AdminGroups;
user_bind_template "cn={username},ou=People,{root}";
}

Groups in different subtrees:

For cases that users from a variety of groups will be logging in, and groups could belong to different LDAP subtrees, a configuration like the following might be needed:

auth_ldap ldap://localhost/dc=company,dc=com {
group_search_base "";
group_filter "member={username}";
user_bind_template "{username}@company.com";
user_filter "userPrincipalName={userBind}";
}
 

Secure LDAP:

If you're using secure LDAP, you can replace ldap protocol with ldaps protocol in all of the above examples. For example:

auth_ldap ldaps://localhost/dc=company,dc=com {
group_filter "member={userDN}";
user_bind_template "cn={username},ou=People,{root}";
}

 

Basic Active Directory Configuration:

For some Active Directory structures a very simple configuration listed below will work:

auth_active_dir ldaps://localhost/dc=company,dc=com company.com{
}


This configuration uses the default values provided for user_bind_template and user_filter to bind the user. And it behaves the same as the following configuration:

auth_active_dir ldaps://localhost/dc=company,dc=com company.com{
user_bind_template "{username}@company.com";
user_filter "userPrincipalName={userBind}";
}

With this configuration, a user logging in as "kim" will see the following in the shiny-server.log:

[TRACE] shiny-server - Attempting to bind LDAP user 'kim@company.com'
..
[TRACE] shiny-server - Using user DN: CN=Kim Smith,CN=Users,DC=company,DC=com


If the configuration has an incorrect filter pattern, as in the following example:

auth_active_dir ldaps://localhost/dc=company,dc=com company.com{
user_bind_template "{username}@company.com";
user_filter "userPrincipalName={username}";
}

authentication will fail. A user logging in as "kim" will see the following in the shiny-server.log:

[TRACE] shiny-server - Attempting to bind LDAP user 'kim@company.com'
..
[WARN] shiny-server - Unable to find any user using the LDAP query '(userPrincipalName=kim)' with base 'cn=Users,DC=company,dc=com'
INFO] shiny-server - Failed login attempt for user: 'kim'

 

You can further define user_search_base directive to specify the subtree in which users are stored. The default value for this is cn=Users. Not defining user_search_base is similar to defining it as follows:

auth_active_dir ldaps://localhost/dc=company,dc=com company.com{
user_filter "userPrincipalName={userBind}";
user_search_base "CN=Users";
}

With this configuration, a user logging in as "kim" will see the following in the shiny-server.log:

[TRACE] shiny-server - Attempting to bind LDAP user 'kim@company.com'
..
[TRACE] shiny-server - Using user DN: CN=Kim Smith,CN=Users,DC=company,DC=com


Notice the pattern for the DN in the last line which uses CN=Users. Change the user_search_base based on the structure of your Active Directory and how/where the users are stored. For example if users are in Corporate subtree, use the following:

auth_active_dir ldaps://localhost/dc=company,dc=com company.com{
user_filter "userPrincipalName={userBind}";
user_search_base "CN=Corporate";
}


If you notice error messages like the following in the shiny-server.log file:

[ERROR] shiny-server - Error with LDAP query: 0000208D: NameErr: DSID-0310020A, problem 2001 (NO_OBJECT), data 0, best match of:
'DC=company,DC=com'

this could indicate that the pattern defined in user_search_base is incorrect.

 

Active Directory and groups

As mentioned earlier, Shiny Server Pro provides the option to authorize access to Admin and/or applications based on group membership.
The default value of group_filter for auth_active_dir is: member:1.2.840.113556.1.4.1941:={userDN}
Not defining group_filter is similar to using the following configuration:

auth_active_dir ldaps://localhost/dc=company,dc=com company.com{
user_filter "userPrincipalName={userBind}";
group_filter "member:1.2.840.113556.1.4.1941:={userDN}";
}

With this configuration, a user logging in as "kim" will see the following in the shiny-server.log:

[TRACE] shiny-server - Attempting to bind LDAP user 'kim@company.com'
..
[TRACE] shiny-server - Using user DN: CN=Kim Smith,CN=Users,DC=company,DC=com
..
[TRACE] shiny-server - Retrieving groups for user 'CN=Kim Smith,CN=Users,DC=company,DC=com' using filter: '(member:1.2.840.113556.1.4.1941:=CN=Kim Smith,CN=Users,DC=company,DC=com)' in 'cn=Users,DC=company,dc=com'
[TRACE] shiny-server - Discovered groups: kim-grp,managers-grp


Define the correct group_filter pattern based on the structure of your Active Directory and the group/user attributes. For example if you have an attribute called memberID instead of member, use the following configuration:

auth_active_dir ldaps://localhost/dc=company,dc=com company.com{
user_filter "userPrincipalName={userBind}";
group_filter "memberID={userDN}";
}

Note that if you do not use the correct attribute, you will not see any errors in the shiny-server.log file, but there won't be any groups returned by the query, and therefore group-based authorization would fail. What you see in the shiny-server.log file is as follows:

[TRACE] shiny-server - Retrieving groups for user 'CN=Kim Smith,CN=Users,DC=company,DC=com' using filter: '(memberID:=CN=Kim Smith,CN=Users,DC=company,DC=com)' in 'cn=Users,DC=company,dc=com'
[TRACE] shiny-server - Discovered groups:


Notice the empty list of "discovered groups".

 

Groups in different Active Directory subtrees:

For cases that users from a variety of groups will be logging in, and groups could belong to different Active Directory subtrees, a configuration like the following might be needed:

auth_active_dir ldaps://localhost/dc=company,dc=com company.com{
user_filter "userPrincipalName={userBind}";
group_filter "member={userDN}";
group_search_base "";
}

 

Too many groups:

There could be cases where a user belongs to too many groups. This could cause problems if the returned list of groups is a string of more than (roughly) 3K characters. For such cases we recommend that you filter the groups further by defining a pattern match as in the following example:

auth_active_dir ldaps://localhost/dc=company,dc=com company.com{
user_filter "userPrincipalName={userBind}";
group_filter "&(cn=*Shiny*)(member={userDN})";
group_search_base "";
}

For details on how to define query patterns refer to the following LDAP documentation:

https://technet.microsoft.com/en-us/library/aa996205%28v=exchg.65%29.aspx

 

Double Bind:

Shiny Server Pro supports double-bind to LDAP/AD. This is done by defining base_bind directive which specifies a user DN and password for the initial LDAP bind operation. The authenticated connection allows Shiny Server Pro to search for a user's DN. The discovered DN is subsequently provided to a second bind operation.

auth_active_dir ldaps://localhost/dc=company,dc=com company.com{
base_bind "CN=Jim Jones,CN=Users,{root}" "<path_to_password_file>";
user_filter "userPrincipalName={userBind}";
group_filter "member={userDN}";
group_search_base cn=Users;
}

With this configuration, a user logging in as "kim" will see the following in the shiny-server.log:

[TRACE] shiny-server - Attempting to bind LDAP user 'CN=Jim Jones,CN=Users,DC=company,dc=com'
...
[TRACE] shiny-server - Attempting to bind LDAP user 'CN=Kim Smith,CN=Users,DC=company,DC=com'
...
[TRACE] shiny-server - Retrieving groups for user 'CN=Kim Smith,CN=Users,DC=company,DC=com' using filter: '(member=CN=Kim Smith,CN=Users,DC=company,DC=com)' in 'cn=Users,DC=company,dc=com'
[TRACE] shiny-server - Discovered groups: kim-grp, managers

 

Note that user_filter directive must be defined whenever using base_bind with auth_ldap.

 

 

 

 

 

 

 

Comments