def authenticate(self, request, auth_info, auth_context): """Authenticate user.""" # NOTE(notmorgan): This is not super pythonic, but we lean on the # __setitem__ method in auth_context to handle edge cases and security # of the attributes set by the plugins. This check to ensure # `auth_context` is an instance of AuthContext is extra insurance and # will prevent regressions. if not isinstance(auth_context, core.AuthContext): LOG.error( '`auth_context` passed to the Auth controller ' '`authenticate` method is not of type ' '`keystone.auth.core.AuthContext`. For security ' 'purposes this is required. This is likely a programming ' 'error. Received object of type `%s`', type(auth_context)) raise exception.Unauthorized( _('Cannot Authenticate due to internal error.')) # The 'external' method allows any 'REMOTE_USER' based authentication # In some cases the server can set REMOTE_USER as '' instead of # dropping it, so this must be filtered out if request.remote_user: try: external = core.get_auth_method('external') resp = external.authenticate(request, auth_info) if resp and resp.status: # NOTE(notmorgan): ``external`` plugin cannot be multi-step # it is either a plain success/fail. auth_context.setdefault('method_names', []).insert(0, 'external') # NOTE(notmorgan): All updates to auth_context is handled # here in the .authenticate method. auth_context.update(resp.response_data or {}) except exception.AuthMethodNotSupported: # This will happen there is no 'external' plugin registered # and the container is performing authentication. # The 'kerberos' and 'saml' methods will be used this way. # In those cases, it is correct to not register an # 'external' plugin; if there is both an 'external' and a # 'kerberos' plugin, it would run the check on identity twice. LOG.debug("No 'external' plugin is registered.") except exception.Unauthorized: # If external fails then continue and attempt to determine # user identity using remaining auth methods LOG.debug("Authorization failed for 'external' auth method.") # need to aggregate the results in case two or more methods # are specified auth_response = {'methods': []} for method_name in auth_info.get_method_names(): method = core.get_auth_method(method_name) resp = method.authenticate(request, auth_info.get_method_data(method_name)) if resp: if resp.status: auth_context.setdefault('method_names', []).insert(0, method_name) # NOTE(notmorgan): All updates to auth_context is handled # here in the .authenticate method. If the auth attempt was # not successful do not update the auth_context resp_method_names = resp.response_data.pop( 'method_names', []) auth_context['method_names'].extend(resp_method_names) auth_context.update(resp.response_data or {}) elif resp.response_body: auth_response['methods'].append(method_name) auth_response[method_name] = resp.response_body if auth_response["methods"]: # authentication continuation required raise exception.AdditionalAuthRequired(auth_response) if 'user_id' not in auth_context: msg = _('User not found by auth plugin; authentication failed') LOG.warning(msg) raise exception.Unauthorized(msg)
def authenticate(self, request, auth_info, auth_context): """Authenticate user.""" # NOTE(notmorgan): This is not super pythonic, but we lean on the # __setitem__ method in auth_context to handle edge cases and security # of the attributes set by the plugins. This check to ensure # `auth_context` is an instance of AuthContext is extra insurance and # will prevent regressions. if not isinstance(auth_context, core.AuthContext): LOG.error( '`auth_context` passed to the Auth controller ' '`authenticate` method is not of type ' '`keystone.auth.controllers.AuthContext`. For security ' 'purposes this is required. This is likely a programming ' 'error. Received object of type `%s`', type(auth_context)) raise exception.Unauthorized( _('Cannot Authenticate due to internal error.')) # The 'external' method allows any 'REMOTE_USER' based authentication # In some cases the server can set REMOTE_USER as '' instead of # dropping it, so this must be filtered out if request.remote_user: try: external = core.get_auth_method('external') resp = external.authenticate(request, auth_info) if resp and resp.status: # NOTE(notmorgan): ``external`` plugin cannot be multi-step # it is either a plain success/fail. auth_context.setdefault( 'method_names', []).insert(0, 'external') # NOTE(notmorgan): All updates to auth_context is handled # here in the .authenticate method. auth_context.update(resp.response_data or {}) except exception.AuthMethodNotSupported: # This will happen there is no 'external' plugin registered # and the container is performing authentication. # The 'kerberos' and 'saml' methods will be used this way. # In those cases, it is correct to not register an # 'external' plugin; if there is both an 'external' and a # 'kerberos' plugin, it would run the check on identity twice. LOG.debug("No 'external' plugin is registered.") except exception.Unauthorized: # If external fails then continue and attempt to determine # user identity using remaining auth methods LOG.debug("Authorization failed for 'external' auth method.") # need to aggregate the results in case two or more methods # are specified auth_response = {'methods': []} for method_name in auth_info.get_method_names(): method = core.get_auth_method(method_name) resp = method.authenticate(request, auth_info.get_method_data(method_name)) if resp: if resp.status: auth_context.setdefault( 'method_names', []).insert(0, method_name) # NOTE(notmorgan): All updates to auth_context is handled # here in the .authenticate method. If the auth attempt was # not successful do not update the auth_context resp_method_names = resp.response_data.pop( 'method_names', []) auth_context['method_names'].extend(resp_method_names) auth_context.update(resp.response_data or {}) elif resp.response_body: auth_response['methods'].append(method_name) auth_response[method_name] = resp.response_body if auth_response["methods"]: # authentication continuation required raise exception.AdditionalAuthRequired(auth_response) if 'user_id' not in auth_context: msg = _('User not found by auth plugin; authentication failed') LOG.warning(msg) raise exception.Unauthorized(msg)