Skip to content

Smartcard configuration against Active Directory throws 500

Summary

A federal customer is trying to set up Smartcard authentication against an Active Directory server but they're getting a 500 error.

Everything in their setup looks right, and they can login with standard LDAP. The failure comes about when using the Smartcard.

At this point we're uncertain as to whether Smartcard authentication supports Active Directory or not.

  • If it is supported, then how can we get this to work?
  • If it's not supported, we should document that and evaluate if and how we can support it.

Steps to reproduce

On GitLab 13.7.0, set up Smartcard authentication against an Active Directory server according to the documentation.

Their LDAP & Smartcard configuration:

gitlab_rails['ldap_enabled'] = true
gitlab_rails['prevent_ldap_sign_in'] = false
###! **remember to close this block with 'EOS' below**
gitlab_rails['ldap_servers'] = YAML.load <<-'EOS'
 main:
   label: 'Active Directory'
   host: 'redacted.redacted'
   port:389
   uid: 'sAMAccountName'
   bind_dn: 'cn=redacted'
   password:'redacted'
   encryption: 'plain' # "start_tls" or "simple_tls" or "plain"
   verify_certificates: false
   smartcard_auth: optional
   active_directory: true
   allow_username_or_email_login: false
   block_auto_created_users: false
   base: 'redacted'
   attributes:
     username:'sAMAccountName'
     name: 'cn'
     first_name:'givinName'
     last_name: 'sn'
   group_base:'redacted'
   admin_group: 'admins'
EOS

### Smartcard authentication settings

gitlab_rails['smartcard_enabled'] = true
gitlab_rails['smartcard_ca_file'] = "/etc/gitlab/trusted-certs/redactedcert.pem"
gitlab_rails['smartcard_client_certificate_required_port'] = 3444

The certs were correctly added to the /etc/gitlab/trusted-certs dir. Once reconfigured, logging in throws an error.

What is the current bug behavior?

On login, the following error is thrown in the production_json.log:

"exception.class":"NoMethodError","exception.message":"undefined method `dn' for nil:NilClass","exception.backtrace":["ee/lib/gitlab/auth/smartcard/ldap_certificate.rb:20:in `find_user'","ee/lib/gitlab/auth/smartcard/base.rb:36:in `find_or_create_user'","ee/app/controllers/smartcard_controller.rb:58:in `sign_in_with'","ee/app/controllers/smartcard_controller.rb:23:in `verify_certificate'","ee/lib/gitlab/ip_address_state.rb:10:in `with'","ee/app/controllers/ee/application_controller.rb:44:in `set_current_ip_address'","app/controllers/application_controller.rb:486:in `set_current_admin'","lib/gitlab/session.rb:11:in `with_session'","app/controllers/application_controller.rb:477:in `set_session_storage'","lib/gitlab/i18n.rb:73:in `with_locale'","lib/gitlab/i18n.rb:79:in `with_user_locale'","app/controllers/application_controller.rb:471:in `set_locale'","app/controllers/application_controller.rb:464:in `block in set_current_context'","lib/gitlab/application_context.rb:63:in `block in use'","lib/gitlab/application_context.rb:63:in `use'","lib/gitlab/application_context.rb:24:in `with_context'","app/controllers/application_controller.rb:455:in `set_current_context'","lib/gitlab/metrics/elasticsearch_rack_middleware.rb:16:in `call'","lib/gitlab/middleware/rails_queue_duration.rb:33:in `call'","lib/gitlab/metrics/rack_middleware.rb:16:in `block in call'","lib/gitlab/metrics/transaction.rb:56:in `run'","lib/gitlab/metrics/rack_middleware.rb:16:in `call'","lib/gitlab/request_profiler/middleware.rb:17:in `call'","lib/gitlab/jira/middleware.rb:19:in `call'","lib/gitlab/middleware/go.rb:20:in `call'","lib/gitlab/etag_caching/middleware.rb:21:in `call'","lib/gitlab/middleware/multipart.rb:172:in `call'","lib/gitlab/middleware/read_only/controller.rb:50:in `call'","lib/gitlab/middleware/read_only.rb:18:in `call'","lib/gitlab/middleware/same_site_cookies.rb:27:in `call'","lib/gitlab/middleware/handle_malformed_strings.rb:21:in `call'","lib/gitlab/middleware/basic_health_check.rb:25:in `call'","lib/gitlab/middleware/handle_ip_spoof_attack_error.rb:25:in `call'","lib/gitlab/middleware/request_context.rb:21:in `call'","config/initializers/fix_local_cache_middleware.rb:11:in `call'","lib/gitlab/metrics/requests_rack_middleware.rb:76:in `call'","lib/gitlab/middleware/release_env.rb:12:in

Here's the line it's failing on, where the ldap_user method is failing to get defined because find_by_certificate_issuer_and_serial doesn't produce a ldap user.

     def ldap_user
       @ldap_user ||= ::Gitlab::Auth::Ldap::Person.find_by_certificate_issuer_and_serial(
         @certificate.issuer.to_s(OpenSSL::X509::Name::RFC2253),
         @certificate.serial.to_s,
         adapter)
     end

At this point we're not sure if this is because of a configuration issue or something else.

It looks like Active Directory doesn't support the certificateExactMatch matching rule, which is a requirement for using the Smartcard, but this is difficult to either confirm or refute. I asked the customer to use ldapsearch to search for a user's userCertificate using this matching rule, with "(userCertificate:2.5.13.34:=SAMPLE_USER_CERT_VALUE)", and that returned 0 entries. However, I'm not positive I asked him to run it correctly. Here's the format:

# Format of command ran
ldapsearch -D "cn=admin,dc=ldap-testing,dc=example,dc=com" \
  -w Password1 \
  -p 389 \
  -h 127.0.0.1 \
  -b "dc=ldap-testing,dc=example,dc=com" \
  "(userCertificate:2.5.13.34:=SAMPLE_USER_CERT_VALUE)"

What is the expected correct behavior?

Smartcard authentication against Active Directory should just work.