Since this report concerns a possible security risk, an incomplete
security advisory task has been added while the core security reviewers
for the affected project or projects confirm the bug and discuss the
scope of any vulnerability along with potential solutions.

** Also affects: ossa
   Importance: Undecided
       Status: New

** Changed in: ossa
       Status: New => Incomplete

** Description changed:

+ This issue is being treated as a potential security risk under embargo.
+ Please do not make any public mention of embargoed (private) security
+ vulnerabilities before their coordinated publication by the OpenStack
+ Vulnerability Management Team in the form of an official OpenStack
+ Security Advisory. This includes discussion of the bug or associated
+ fixes in public forums such as mailing lists, code review systems and
+ bug trackers. Please also avoid private disclosure to other individuals
+ not already approved for access to this information, and provide this
+ same reminder to those who are made aware of the issue prior to
+ publication. All discussion should remain confined to this private bug
+ report, and any proposed fixes should be added to the bug as
+ attachments.
+ 
  When keystone.conf is defined with external auth , all V2.0 API calls do
  not get intercepted by the defined external auth.
- 
  
  this is my keystone.conf
  [auth]
  methods=password,token,external
  external=keystone.auth.plugins.idm_external.IDMDefaultDomain
- 
  
  V.20 CURL to initiate external auth.
  curl -X POST -d '{"auth":{}}' -H "Content-type: application/json" -H 
"REMOTE_USER: admin" http://localhost:5000/v2.0/tokens
  
  What I'm seeing is the call gets to the keystone/token/controller.py,
  where it checks for the auth{} and executes the external authentication
  
-         if "token" in auth:
-             # Try to authenticate using a token
-             auth_info = self._authenticate_token(
-                 context, auth)
-         else:
-             # Try external authentication
-             try:
-                 auth_info = self._authenticate_external(
-                     context, auth)
-             except ExternalAuthNotApplicable:
-                 # Try local authentication
-                 auth_info = self._authenticate_local(
-                     context, auth)
+         if "token" in auth:
+             # Try to authenticate using a token
+             auth_info = self._authenticate_token(
+                 context, auth)
+         else:
+             # Try external authentication
+             try:
+                 auth_info = self._authenticate_external(
+                     context, auth)
+             except ExternalAuthNotApplicable:
+                 # Try local authentication
+                 auth_info = self._authenticate_local(
+                     context, auth)
  
  ...
-    def _authenticate_external(self, context, auth):
-         """Try to authenticate an external user via REMOTE_USER variable.
+    def _authenticate_external(self, context, auth):
+         """Try to authenticate an external user via REMOTE_USER variable.
  
-         Returns auth_token_data, (user_ref, tenant_ref, metadata_ref)
-         """
-         if 'REMOTE_USER' not in context.get('environment', {}):
-             raise ExternalAuthNotApplicable()
+         Returns auth_token_data, (user_ref, tenant_ref, metadata_ref)
+         """
+         if 'REMOTE_USER' not in context.get('environment', {}):
+             raise ExternalAuthNotApplicable()
  
-         #NOTE(jamielennox): xml and json differ and get confused about what
-         # empty auth should look like so just reset it.
-         if not auth:
-             auth = {}
+         #NOTE(jamielennox): xml and json differ and get confused about what
+         # empty auth should look like so just reset it.
+         if not auth:
+             auth = {}
  
-         username = context['environment']['REMOTE_USER']
-         try:
-             user_ref = self.identity_api.get_user_by_name(
-                 username, CONF.identity.default_domain_id)
-             user_id = user_ref['id']
-         except exception.UserNotFound as e:
-             raise exception.Unauthorized(e)
+         username = context['environment']['REMOTE_USER']
+         try:
+             user_ref = self.identity_api.get_user_by_name(
+                 username, CONF.identity.default_domain_id)
+             user_id = user_ref['id']
+         except exception.UserNotFound as e:
+             raise exception.Unauthorized(e)
  
-         metadata_ref = {}
-         tenant_id = self._get_project_id_from_auth(auth)
-         tenant_ref, metadata_ref['roles'] = self._get_project_roles_and_ref(
-             user_id, tenant_id)
+         metadata_ref = {}
+         tenant_id = self._get_project_id_from_auth(auth)
+         tenant_ref, metadata_ref['roles'] = self._get_project_roles_and_ref(
+             user_id, tenant_id)
  
-         expiry = core.default_expire_time()
-         bind = None
-         if ('kerberos' in CONF.token.bind and
-                 context['environment'].
-                 get('AUTH_TYPE', '').lower() == 'negotiate'):
-             bind = {'kerberos': username}
+         expiry = core.default_expire_time()
+         bind = None
+         if ('kerberos' in CONF.token.bind and
+                 context['environment'].
+                 get('AUTH_TYPE', '').lower() == 'negotiate'):
+             bind = {'kerberos': username}
  
-         return (user_ref, tenant_ref, metadata_ref, expiry, bind)
+         return (user_ref, tenant_ref, metadata_ref, expiry, bind)
  
- 
- The  _authenticate_external should not assume and have its own REMOTE_USER 
implementation,  instead it should look for the external method defined in 
keystone.conf and appropriately call the defined external class.
+ The  _authenticate_external should not assume and have its own
+ REMOTE_USER implementation,  instead it should look for the external
+ method defined in keystone.conf and appropriately call the defined
+ external class.
  
  The V3 call works fine and calls the right external class defined.
  curl -X POST -d 
'{"auth":{"identity":{"methods":["external"],"external":{}}}}'  -H 
"REMOTE_USER:admin" -H "Content-type: application/json" 
http://localhost:5000/v3/auth/tokens
  
  This is potentially a security hole as well, which will allow all V2
  API's to get Keystone token w/o password.

** Description changed:

- This issue is being treated as a potential security risk under embargo.
- Please do not make any public mention of embargoed (private) security
- vulnerabilities before their coordinated publication by the OpenStack
- Vulnerability Management Team in the form of an official OpenStack
- Security Advisory. This includes discussion of the bug or associated
- fixes in public forums such as mailing lists, code review systems and
- bug trackers. Please also avoid private disclosure to other individuals
- not already approved for access to this information, and provide this
- same reminder to those who are made aware of the issue prior to
- publication. All discussion should remain confined to this private bug
- report, and any proposed fixes should be added to the bug as
- attachments.
- 
  When keystone.conf is defined with external auth , all V2.0 API calls do
  not get intercepted by the defined external auth.
  
  this is my keystone.conf
  [auth]
  methods=password,token,external
  external=keystone.auth.plugins.idm_external.IDMDefaultDomain
  
  V.20 CURL to initiate external auth.
  curl -X POST -d '{"auth":{}}' -H "Content-type: application/json" -H 
"REMOTE_USER: admin" http://localhost:5000/v2.0/tokens
  
  What I'm seeing is the call gets to the keystone/token/controller.py,
  where it checks for the auth{} and executes the external authentication
  
          if "token" in auth:
              # Try to authenticate using a token
              auth_info = self._authenticate_token(
                  context, auth)
          else:
              # Try external authentication
              try:
                  auth_info = self._authenticate_external(
                      context, auth)
              except ExternalAuthNotApplicable:
                  # Try local authentication
                  auth_info = self._authenticate_local(
                      context, auth)
  
  ...
     def _authenticate_external(self, context, auth):
          """Try to authenticate an external user via REMOTE_USER variable.
  
          Returns auth_token_data, (user_ref, tenant_ref, metadata_ref)
          """
          if 'REMOTE_USER' not in context.get('environment', {}):
              raise ExternalAuthNotApplicable()
  
          #NOTE(jamielennox): xml and json differ and get confused about what
          # empty auth should look like so just reset it.
          if not auth:
              auth = {}
  
          username = context['environment']['REMOTE_USER']
          try:
              user_ref = self.identity_api.get_user_by_name(
                  username, CONF.identity.default_domain_id)
              user_id = user_ref['id']
          except exception.UserNotFound as e:
              raise exception.Unauthorized(e)
  
          metadata_ref = {}
          tenant_id = self._get_project_id_from_auth(auth)
          tenant_ref, metadata_ref['roles'] = self._get_project_roles_and_ref(
              user_id, tenant_id)
  
          expiry = core.default_expire_time()
          bind = None
          if ('kerberos' in CONF.token.bind and
                  context['environment'].
                  get('AUTH_TYPE', '').lower() == 'negotiate'):
              bind = {'kerberos': username}
  
          return (user_ref, tenant_ref, metadata_ref, expiry, bind)
  
  The  _authenticate_external should not assume and have its own
  REMOTE_USER implementation,  instead it should look for the external
  method defined in keystone.conf and appropriately call the defined
  external class.
  
  The V3 call works fine and calls the right external class defined.
  curl -X POST -d 
'{"auth":{"identity":{"methods":["external"],"external":{}}}}'  -H 
"REMOTE_USER:admin" -H "Content-type: application/json" 
http://localhost:5000/v3/auth/tokens
  
  This is potentially a security hole as well, which will allow all V2
  API's to get Keystone token w/o password.

** Information type changed from Public to Public Security

-- 
You received this bug notification because you are a member of Yahoo!
Engineering Team, which is subscribed to Keystone.
https://bugs.launchpad.net/bugs/1461728

Title:
  V2.0 API not calling defined external auth

Status in OpenStack Identity (Keystone):
  New
Status in OpenStack Security Advisories:
  Incomplete

Bug description:
  When keystone.conf is defined with external auth , all V2.0 API calls
  do not get intercepted by the defined external auth.

  this is my keystone.conf
  [auth]
  methods=password,token,external
  external=keystone.auth.plugins.idm_external.IDMDefaultDomain

  V.20 CURL to initiate external auth.
  curl -X POST -d '{"auth":{}}' -H "Content-type: application/json" -H 
"REMOTE_USER: admin" http://localhost:5000/v2.0/tokens

  What I'm seeing is the call gets to the keystone/token/controller.py,
  where it checks for the auth{} and executes the external
  authentication

          if "token" in auth:
              # Try to authenticate using a token
              auth_info = self._authenticate_token(
                  context, auth)
          else:
              # Try external authentication
              try:
                  auth_info = self._authenticate_external(
                      context, auth)
              except ExternalAuthNotApplicable:
                  # Try local authentication
                  auth_info = self._authenticate_local(
                      context, auth)

  ...
     def _authenticate_external(self, context, auth):
          """Try to authenticate an external user via REMOTE_USER variable.

          Returns auth_token_data, (user_ref, tenant_ref, metadata_ref)
          """
          if 'REMOTE_USER' not in context.get('environment', {}):
              raise ExternalAuthNotApplicable()

          #NOTE(jamielennox): xml and json differ and get confused about what
          # empty auth should look like so just reset it.
          if not auth:
              auth = {}

          username = context['environment']['REMOTE_USER']
          try:
              user_ref = self.identity_api.get_user_by_name(
                  username, CONF.identity.default_domain_id)
              user_id = user_ref['id']
          except exception.UserNotFound as e:
              raise exception.Unauthorized(e)

          metadata_ref = {}
          tenant_id = self._get_project_id_from_auth(auth)
          tenant_ref, metadata_ref['roles'] = self._get_project_roles_and_ref(
              user_id, tenant_id)

          expiry = core.default_expire_time()
          bind = None
          if ('kerberos' in CONF.token.bind and
                  context['environment'].
                  get('AUTH_TYPE', '').lower() == 'negotiate'):
              bind = {'kerberos': username}

          return (user_ref, tenant_ref, metadata_ref, expiry, bind)

  The  _authenticate_external should not assume and have its own
  REMOTE_USER implementation,  instead it should look for the external
  method defined in keystone.conf and appropriately call the defined
  external class.

  The V3 call works fine and calls the right external class defined.
  curl -X POST -d 
'{"auth":{"identity":{"methods":["external"],"external":{}}}}'  -H 
"REMOTE_USER:admin" -H "Content-type: application/json" 
http://localhost:5000/v3/auth/tokens

  This is potentially a security hole as well, which will allow all V2
  API's to get Keystone token w/o password.

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

-- 
Mailing list: https://launchpad.net/~yahoo-eng-team
Post to     : yahoo-eng-team@lists.launchpad.net
Unsubscribe : https://launchpad.net/~yahoo-eng-team
More help   : https://help.launchpad.net/ListHelp

Reply via email to