Merge pull request #8369 from opf/feature/ldap-ca-file

[33345] Allow to override path to the CA used by LDAP connections

[ci skip]
pull/8374/head
Oliver Günther 5 years ago committed by GitHub
commit 00b42adde6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      app/models/ldap_auth_source.rb
  2. 9
      config/configuration.yml.example
  3. 94
      docs/system-admin-guide/authentication/ldap-authentication/README.md
  4. BIN
      docs/system-admin-guide/authentication/ldap-authentication/Screenshot-from-2018-11-01-13-47-42.png
  5. BIN
      docs/system-admin-guide/authentication/ldap-authentication/ldap-attribute-mapping.png
  6. BIN
      docs/system-admin-guide/authentication/ldap-authentication/ldap-details.png
  7. BIN
      docs/system-admin-guide/authentication/ldap-authentication/ldap-host-and-security.png
  8. 0
      docs/system-admin-guide/authentication/ldap-authentication/ldap-index-page.png
  9. BIN
      docs/system-admin-guide/authentication/ldap-authentication/ldap-settings.png
  10. BIN
      docs/system-admin-guide/authentication/ldap-authentication/ldap-system-user.png
  11. 8
      lib/open_project/configuration.rb
  12. 5
      lib/open_project/configuration/helpers.rb
  13. 13
      spec/models/ldap_auth_source_spec.rb

@ -134,11 +134,12 @@ class LdapAuthSource < AuthSource
end
def ldap_encryption
if tls_mode == 'plain_ldap'
nil
else
tls_mode.to_sym
end
return nil if tls_mode.to_s == 'plain_ldap'
{
method: tls_mode.to_sym,
tls_options: OpenProject::Configuration.ldap_tls_options.with_indifferent_access
}
end
# Check if a DN (user record) authenticates with the password

@ -376,6 +376,15 @@ default:
# user: admin
# password: admin
# Overriding LDAP TLS configuration
# You can set other TLS options for the LDAP auth source connection
# They are passed as the `tls_options` to the Net::LDAP gem
# see the following resources for more information
# https://github.com/ruby-ldap/ruby-net-ldap/blob/master/lib/net/ldap.rb
# https://ruby.github.io/openssl/OpenSSL/SSL/SSLContext.html
# For example, to specify a CA file
# ldap_tls_options:
# ca_file: "/path/to/the/root-ca.crt"
# By default, the APIv3 allows authentication through basic auth.
# Uncomment the following line to restrict APIv3 access to session.

@ -23,34 +23,106 @@ To create a new LDAP authentication click on the respective icon.
You will then be able to specify the LDAP configuration. This can be any directory service compatible with the LDAPv3 standard, such as Microsoft Active Directory or openLDAP. The configuration depends on the specific database/applications, through which the authentication with OpenProject is intended.
The following screenshot contains an exemplary configuration for a new LDAP authentication mode. In the following, we will go through all available options.
The following screenshots contain an exemplary configuration for a new LDAP authentication mode. In the following, we will go through all available options.
#### LDAP connection details and security
![Adding a new LDAP authentication server](ldap-host-and-security.png)
In the upper section, you have to specify the connection details of your LDAP server as well as the connection encryption to use.
![Adding a new LDAP authentication server](Screenshot-from-2018-11-01-13-47-42.png)
- **Name:** Arbitrary identifier used to show which authentication source a user is coming from (e.g., in the [Administration > Users view](https://www.openproject.org/help/administration/manage-users/))
- **Host:** Full hostname to the LDAP server
- **Port :** LDAP port. Will usually be 389 for LDAP and 689 for LDAPS connections.
- **LDAPS :** If checked, this will result in NET::LDAP connecting with the *simple_tls* option *enabled.* [Click here to read more details into what this means for connection security.](https://www.rubydoc.info/gems/ruby-net-ldap/Net/LDAP)
- **Port :** LDAP port. Will usually be 389 for LDAP and StartTLS and 636 for LDAP over SSL connections.
- **Connection encryption**: Select the appropriate connection encryption.
- For unencrypted connections, select `none` . No TLS/SSL connection will be established, your connection will be unsecure
- For LDAPS connections (LDAP over SSL), use `simple_tls` , this is an older SSL encryption pattern that uses SSL certificates, but **DOES NOT VERIFY THEM**. Implicit trust in the connection will be placed, but the connection will be encrypted. Some older LDAP servers only support this option
- **Recommended option**: `start_tls` will use TLS to encrypt the connection after connecting to the LDAP server on the unencrypted PORT (`389` by default).
- [Click here to read more details into what these options mean for connection security.](https://www.rubydoc.info/gems/ruby-net-ldap/Net/LDAP)
**Allowing untrusted certifcates for LDAP connections**
If you use `start_tls` , certificate details and host names will be verified on connections as recommended for security. In case you use a custom untrusted certificate authority (CA) that your LDAP is connecting to, you can place this CA in your system's trusted CA store if possible. For some distributions, you will need to specify this CA manually to OpenProject.
You can do this by using the [advanced configuration](https://docs.openproject.org/installation-and-operations/configuration/) function of OpenProject. You can define the CA path by setting the following ENV variable:
```bash
OPENPROJECT_LDAP__TLS__OPTIONS_CA__FILE="/path/to/the/root-ca.crt"
```
or by extending your production configuration of `config/configuration.yml` with the following segment:
```
production:
# .. other settings ..
# ldap_tls_options:
# ca_file: "/path/to/the/root-ca.crt"
```
You can set other TLS options for the LDAP auth source connection. They are passed as the `tls_options` to the Net::LDAP gem and ultimately end up in the `SSLContext` setting of Ruby. You can define the TLS version and other advanced options in case your connections needs it. Most users will not need to change this however.
See the following resources for more information:
- https://github.com/ruby-ldap/ruby-net-ldap/blob/master/lib/net/ldap.rb
- https://ruby.github.io/openssl/OpenSSL/SSL/SSLContext.html
#### LDAP system user credentials
![Defining the system user of the connection](ldap-system-user.png)
Next, you will need to enter a system user that has READ access to the users for identification and synchronization purposes. Note that most operations to the LDAP during authentication will not be using these credentials, but the user-provided credentials in the login form in order to perform a regular user bind to the LDAP.
- **Account:** The full DN of a system users used for looking up user details in the LDAP. It must have read permissions under the Base DN. This will not be used for the user bind upon authentication.
- **Password:** The bind password of the system user’s DN above.
- **On-the-fly user creation:** Check to automatically create users in OpenProject when they first login in OpenProject. It will use the LDAP attribute mapping below to fill out required attributes. The user will be forwarded to a registration screen to complete required attributes if they are missing in the LDAP.
**Attribute mapping**
#### LDAP details
![Defining the details of the connection](ldap-details.png)
Next you can define what sections OpenProject will look for in the LDAP and also if users should be created automatically in OpenProject when they are accessing it. Let's look at the available options:
- **Base DN**: Enter the Base DN to search within for users and groups in the LDAP tree
- **Filter string**: Enter an optional [LDAP RFC4515 filter string](https://tools.ietf.org/search/rfc4515) to further reduce the returned set of users. This allows you to restrict access to OpenProject with a very flexible filter. For group synchronization, only users matching this filter will be added as well.
- **Automatic user creation:** Check to automatically create users in OpenProject when they first login in OpenProject. It will use the LDAP attribute mapping below to fill out required attributes. The user will be forwarded to a registration screen to complete required attributes if they are missing in the LDAP.
#### Attribute mapping
![Defining the attribute map for users](ldap-attribute-mapping.png)
The attribute mapping is used to identify attributes of OpenProject with attributes of the LDAP directory. At least the *login* attribute is required to create DNs from the login credentials.
- **Login:** The login attribute in the ldap. Will be used to construct the DN from `login-attribute=value,`. Most often, this will be *uid.*
- **First name:** The attribute name in the LDAP that maps to first name. Most often, this will be *givenName.* If left empty, user will be prompted to enter upon registration if **on-the-fly-creation** is true.
- **Last name:** The attribute name in the LDAP that maps to last name. Most often, this will be *sn.* If left empty, user will be prompted to enter upon registration if **on-the-fly-creation** is true.
- **Email:** The attribute name in the LDAP that maps to the user’s mail address. This will usually be *mail.* If left empty, user will be prompted to enter upon registration if **on-the-fly-creation** is true.
- **First name:** The attribute name in the LDAP that maps to first name. Most often, this will be *givenName.* If left empty, user will be prompted to enter upon registration if **automatic user creation** is true.
- **Last name:** The attribute name in the LDAP that maps to last name. Most often, this will be *sn.* If left empty, user will be prompted to enter upon registration if **automatic user creation** is true.
- **Email:** The attribute name in the LDAP that maps to the user’s mail address. This will usually be *mail.* If left empty, user will be prompted to enter upon registration if **automatic user creation** is true.
- **Admin:** Specify an attribute that if it has a truthy value, results in the user in OpenProject becoming an admin account. Leave empty to never set admin status from LDAP attributes.
Lastly, click on *Create* to save the LDAP authentication mode. You will be redirected to the index page with the created authentication mode. Click the *test* button to create a test connection using the system user’s bind credentials.
![LDAP authentication mode created](Screenshot-from-2018-11-01-14-03-42.png)
![LDAP authentication mode created](ldap-index-page.png)
With the [OpenProject Enterprise Edition](https://www.openproject.org/enterprise-edition/) it is possible to [synchronize LDAP and OpenProject groups](./ldap-group-synchronization).

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

@ -170,7 +170,10 @@ module OpenProject
'sentry_host' => 'https://sentry.openproject.com',
# Allow connection to Augur
'enterprise_trial_creation_host' => 'https://augur.openproject.com'
'enterprise_trial_creation_host' => 'https://augur.openproject.com',
# Allow override of LDAP options
'ldap_auth_source_tls_options' => nil
}
@config = nil
@ -200,8 +203,7 @@ module OpenProject
# Replace config values for which an environment variable with the same key in upper case
# exists
def override_config!(config, source = default_override_source)
config.keys
.select { |key| source.include? key.upcase }
config.keys.select { |key| source.include? key.upcase }
.each { |key| config[key] = extract_value key, source[key.upcase] }
config.deep_merge! merge_config(config, source)

@ -106,6 +106,11 @@ module OpenProject
uploaders
end
def ldap_tls_options
val = self['ldap_tls_options']
val.presence || {}
end
private
##

@ -41,6 +41,19 @@ describe LdapAuthSource, type: :model do
expect(a.reload.attr_firstname).to eq 'givenName'
end
describe 'overriding tls_options',
with_config: { ldap_tls_options: { ca_file: '/path/to/ca/file' } } do
it 'sets the encryption options for start_tls' do
ldap = LdapAuthSource.new tls_mode: :start_tls
expect(ldap.send(:ldap_encryption)).to eq(method: :start_tls, tls_options: { 'ca_file' => '/path/to/ca/file' })
end
it 'does nothing for plain_ldap' do
ldap = LdapAuthSource.new tls_mode: :plain_ldap
expect(ldap.send(:ldap_encryption)).to eq nil
end
end
describe 'with live LDAP' do
before(:all) do
ldif = Rails.root.join('spec/fixtures/ldap/users.ldif')

Loading…
Cancel
Save