[Openstack-security] [Bug 1254619] Re: external.Default authentication plugin only considers leftmost part of the REMOTE_USER split by "@"

OpenStack Infra 1254619 at bugs.launchpad.net
Sun Jan 12 00:39:14 UTC 2014


Reviewed:  https://review.openstack.org/50362
Committed: https://git.openstack.org/cgit/openstack/keystone/commit/?id=1889ff207561c57587384063d61ef0b6f78457c4
Submitter: Jenkins
Branch:    master

commit 1889ff207561c57587384063d61ef0b6f78457c4
Author: Alvaro Lopez Garcia <aloga at ifca.unican.es>
Date:   Tue Oct 8 11:08:42 2013 +0200

    Fix external auth (REMOTE_USER) plugin support
    
    According to the WSGI specification "REMOTE_USER should be the string
    username of the user, nothing more" [1], therefore no modifications
    should be made to the REMOTE_USER variable and it should be fully
    considered as the username. Otherwise the expected semantics of the
    REMOTE_USER variable change, and an site administrator could get
    undesirable side-effects.
    
    [1] http://wsgi.readthedocs.org/en/latest/specifications/simple_authentication.html#specification
    
    Moreover, it is important to have a consistent behaviour regarding
    external authentication in V2 (not domain aware), V3 with default
    domain and V3 with domain (see Bug #1253484) so that we produce similar
    results with the three methods.
    
    This change aims to solve this issues by removing the split of the
    REMOTE_USER variable by "@" at all:
    
    - In external.DefaultDomain, we cannot split REMOTE_USER by "@". This split
      will cause errors for remote users containing an "@" (not only
      emails, but also X.509 subjects, etc). The external.DefaultDomain plugin
      considers the REMOTE_USER variable as the username, and the configured
      default domain as the domain
    
    - In external.Domain we should not split also the REMOTE_USER by "@". A
      new environment variable (REMOTE_DOMAIN) is introduced, so that any
      external plugin can pass down the right domain for the user. The
      external.Domain plugin considers the REMOTE_USER as the username, the
      REMOTE_DOMAIN as the domain if it is present, otherwise it takes the
      configured default domain.
    
    - Two legacy plugins are also provided with the same behaviour as the
      Havana shipped ones. This plugins should not be used and are provided
      for compatibility reasons (see Bug #1254619)
    
    Closes-Bug: #1254619
    Closes-Bug: #1211233
    Closes-Bug: #1253484
    
    DocImpact: This change breaks backwards compatibility in favour of
    security (see bug #1254619), therefore an upgrade not is needed. It is
    needed to document the new plugins and state clearly the semantics of
    the REMOTE_USER and REMOTE_DOMAIN variable for the WSGI filters. The
    default external authentication plugin has been changed from
    exernal.ExternalDefault to external.Default.
    
    Change-Id: I1b2521a526fa976146dfe2fcf4d4c1851416d8ae


** Changed in: keystone
       Status: In Progress => Fix Committed

-- 
You received this bug notification because you are a member of OpenStack
Security Group, which is subscribed to OpenStack.
https://bugs.launchpad.net/bugs/1254619

Title:
  external.Default authentication plugin only considers leftmost part of
  the REMOTE_USER split by "@"

Status in OpenStack Identity (Keystone):
  Fix Committed
Status in OpenStack Security Advisories:
  Invalid
Status in OpenStack Security Notes:
  In Progress

Bug description:
  Hi there.

  Keystone allows the usage of external authentication. This external
  authentication makes possible for the deployers to integrate external
  euth methods in Keystone. When it is executed as a WSGI application
  (for example when executed behind apache using mod_wsgi) the
  authentication can be made by the web server and the user will be
  passed down using the REMOTE_USER environment variable. It is also
  possible to use external authn by creating a custom WSGI filter that
  will be pipelined. More details of this behaviour can be seen in [0].

  [0] http://docs.openstack.org/developer/keystone/external-auth.html

  Since the Havana release, this code has been refactored and moved to a
  pluggable mechanism under keystone/auth/plugins/external.py. If I am
  not wrong, this was introduced in commit
  88c319e6bce98082f9a90b8b27726793d5366326 [1]. This code is in
  stable/havana since that commit, and is currently in the trunk.

  [1]
  https://github.com/openstack/keystone/commit/88c319e6bce98082f9a90b8b27726793d5366326

  During the review of [2] the ExternalDefault plugin I've realized that
  the way the plugin extracts the username can lead to impersonation.
  The excerpt of code that extracts the username is this one [3]:

      names = remote_user.split('@')
      username = names.pop(0)
      domain_id = CONF.identity.default_domain_id
      user_ref = auth_info.identity_api.get_user_by_name(username,
                                                         domain_id)

  When Keystone is configured to use the defualt domain, the REMOTE_USER
  variable is splited by all the "@" and then only the leftfmost part is
  considered, while the leftovers are discarded. Since a username can
  contain "@" inside (for example when emails are used as usernames)
  "john" "john at example.org" and "john at foobar.net" will all get a token
  belonging to the "john" user.

  [2] https://review.openstack.org/#/c/50362
  [3] https://github.com/openstack/keystone/blob/stable/havana/keystone/auth/plugins/external.py#L39

  External authentication opens the door for any deployer to use any
  authentication mechanism. OpenStack does not ship any external
  authentication mechanism, but it is perfectly possible to use emails
  as the usernames (or usernames containing "@", as X509 certificate
  DNs). For example, a LDAP directory could be configured in Apache to
  let the users in, and set the REMOTE_USER as the username, instead of
  the user DN.

  It is possible to easily reproduce this using devstack as follows:

      ubuntu at test-ks-vuln:~/devstack$ cat > localrc << EOF
      > ENABLED_SERVICES=key,mysql
      > APACHE_ENABLED_SERVICES+=keystone
      > EOF
      ubuntu at test-ks-vuln:~/devstack$ ./stack.sh
      (...)
      ubuntu at test-ks-vuln:~/devstack$ source openrc admin admin
      ubuntu at test-ks-vuln:~/devstack$ keystone user-list
      +----------------------------------+-------+---------+-------------------+
      |                id                |  name | enabled |       email       |
      +----------------------------------+-------+---------+-------------------+
      | dc90b499a1c0499997bd35ba19a2436c | admin |   True  | admin at example.com |
      | 685cd73e645243c2ba81314cbc5ac89a |  demo |   True  |  demo at example.com |
      +----------------------------------+-------+---------+-------------------+
      ubuntu at test-ks-vuln:~/devstack$ keystone tenant-list
      +----------------------------------+--------------------+---------+
      |                id                |        name        | enabled |
      +----------------------------------+--------------------+---------+
      | d5319bc5b7054e0589ad32048813ee1a |       admin        |   True  |
      | badfa689e32a4d9fb7d102a7d92ad3b7 |        demo        |   True  |
      | 110627ae8c534b548d70a5a159ff65ee | invisible_to_admin |   True  |
      | 92484643deb246e680ee3d716a7dfeea |      service       |   True  |
      +----------------------------------+--------------------+---------+
      ubuntu at test-ks-vuln:~/devstack$ keystone tenant-create --name external_users
      +-------------+----------------------------------+
      |   Property  |              Value               |
      +-------------+----------------------------------+
      | description |                                  |
      Listen 5000
      |   enabled   |               True               |
      Listen 5000
      |      id     | 3ac4e3f06a3548378eb26e3be8dc3952 |
      |     name    |          external_users          |
      +-------------+----------------------------------+
      ubuntu at test-ks-vuln:~/devstack$ keystone user-create --name john --tenant d5319bc5b7054e0589ad32048813ee1a --pass secret
      +----------+----------------------------------+
      | Property |              Value               |
      +----------+----------------------------------+
      |  email   |                                  |
      Listen 5000
      | enabled  |               True               |
      |    id    | a8fe063e8a124f89ada9526d401aad98 |
      |   name   |               john               |
      | tenantId | d5319bc5b7054e0589ad32048813ee1a |
      +----------+----------------------------------+
      ubuntu at test-ks-vuln:~/devstack$ keystone user-create --name john at external_user.com --tenant 3ac4e3f06a3548378eb26e3be8dc3952 --pass secret
      +----------+----------------------------------+
      | Property |              Value               |
      +----------+----------------------------------+
      |  email   |                                  |
      | enabled  |               True               |
      |    id    | 6af78b4bdca646a68069d74cdf8e5334 |
      |   name   |      john at external_user.com      |
      | tenantId | 3ac4e3f06a3548378eb26e3be8dc3952 |
      +----------+----------------------------------+

  So far I've two different users. For the shake of simplicity I will
  use Apache's basic authentication, so it is needed to add the
  following excerpt to /etc/apache2/sites-enabled/keystone:

      Listen 5001
      <VirtualHost *:5001>
          WSGIDaemonProcess keystone-public2 processes=5 threads=1 user=ubuntu
          WSGIProcessGroup keystone-public2
          WSGIScriptAlias / /var/www/keystone/main
          WSGIApplicationGroup %{GLOBAL}
          ErrorLog /var/log/apache2/keystone
          LogLevel debug
          CustomLog /var/log/apache2/access.log combined
          <Location />
              AuthType Basic
              AuthName "Restricted Files"
              AuthBasicProvider file
              AuthUserFile /opt/stack/htpasswd
              Require valid-user
          </Location>
      </VirtualHost>

  And then, create the external user, and authenticate with it:

      ubuntu at test-ks-vuln:~/devstack$ sudo htpasswd -c /opt/stack/htpasswd john at external_user.com
      New password:
      Re-type new password:
      Adding password for user john at external_user.com
      ubuntu at test-ks-vuln:~/devstack$ sudo /etc/init.d/apache2 restart
      * Restarting web server apache2
      * ... waiting
      ubuntu at test-ks-vuln:~/devstack$
      ubuntu at test-ks-vuln:~$ curl --user john at external_user.com:secret -d '{"auth": {"identity":{ "methods": []}}}' -H "Content-type: application/json" http://172.16.0.63:5001/v3/auth/tokens |python -mjson.tool
        % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                       Dload  Upload   Total   Spent    Left  Speed
      100  1134  100  1095  100    39   2301     81 --:--:-- --:--:-- --:--:--  2300
      {
          "token": {
              "catalog": [
                  {
                      "endpoints": [
                          {
                              "id": "d0b2b692496a4d2c8a70e63543782aed",
                              "interface": "internal",
                              "legacy_endpoint_id": "59eddafa29194ef5a1d221aad17f2f2e",
                              "region": "RegionOne",
                              "url": "http://172.16.0.63:5000/v2.0"
                          },
                          {
                              "id": "da7fe597a1b84529910e890807b47bdb",
                              "interface": "admin",
                              "legacy_endpoint_id": "59eddafa29194ef5a1d221aad17f2f2e",
                              "region": "RegionOne",
                              "url": "http://172.16.0.63:35357/v2.0"
                          },
                          {
                              "id": "eeda9fbcffe94588ad15689d33f2c1e9",
                              "interface": "public",
                              "legacy_endpoint_id": "59eddafa29194ef5a1d221aad17f2f2e",
                              "region": "RegionOne",
                              "url": "http://172.16.0.63:5000/v2.0"
                          }
                      ],
                      "id": "14a4bd4966b74503ab2fb47836101824",
                      "type": "identity"
                  }
              ],
              "expires_at": "2013-11-26T23:04:55.341085Z",
              "extras": {},
              "issued_at": "2013-11-25T23:04:55.341121Z",
              "methods": [],
              "project": {
                  "domain": {
                      "id": "default",
                      "name": "Default"
                  },
                  "id": "d5319bc5b7054e0589ad32048813ee1a",
                  "name": "admin"
              },
              "roles": [
                  {
                      "id": "9fe2ff9ee4384b1894a90878d3e92bab",
                      "name": "_member_"
                  }
              ],
              "user": {
                  "domain": {
                      "id": "default",
                      "name": "Default"
                  },
                  "id": "a8fe063e8a124f89ada9526d401aad98",
                  "name": "john"
              }
          }
      }

  As you can see, I am getting the id for the user "john"
  (a8fe063e8a124f89ada9526d401aad98) instead of the user
  "john at example_user.com" (6af78b4bdca646a68069d74cdf8e5334). The patch
  in [2] should fix this issue (although it was initially unrelated)
  since it does not split the username when using the ExternalDefault
  plugin.

To manage notifications about this bug go to:
https://bugs.launchpad.net/keystone/+bug/1254619/+subscriptions




More information about the Openstack-security mailing list