def _authorize_user(self, username, key, req): """Generates a new token and assigns it to a user. username - string key - string API key req - wsgi.Request object """ ctxt = context.get_admin_context() project_id = req.headers.get('X-Auth-Project-Id') if project_id is None: # If the project_id is not provided in the headers, be forgiving to # the user and set project_id based on a valid project of theirs. user = self.auth.get_user_from_access_key(key) projects = self.auth.get_projects(user.id) if not projects: raise webob.exc.HTTPUnauthorized() project_id = projects[0].id try: user = self.auth.get_user_from_access_key(key) except exception.NotFound: LOG.warn(_("User not found with provided API key.")) user = None if user and utils.strcmp_const_time(user.name, username): token_hash = hashlib.sha1( '%s%s%f' % (username, key, time.time())).hexdigest() token_dict = {} token_dict['token_hash'] = token_hash token_dict['cdn_management_url'] = '' os_url = req.url.strip('/') os_url += '/' + project_id token_dict['server_management_url'] = os_url token_dict['storage_url'] = '' token_dict['user_id'] = user.id token = self.db.auth_token_create(ctxt, token_dict) return token, user elif user and user.name != username: msg = _("Provided API key is valid, but not for user " "'%(username)s'") % locals() LOG.warn(msg) return None, None
def _authorize_user(self, username, key, req): """Generates a new token and assigns it to a user. username - string key - string API key req - wsgi.Request object """ ctxt = context.get_admin_context() project_id = req.headers.get('X-Auth-Project-Id') if project_id is None: # If the project_id is not provided in the headers, be forgiving to # the user and set project_id based on a valid project of theirs. user = self.auth.get_user_from_access_key(key) projects = self.auth.get_projects(user.id) if not projects: raise webob.exc.HTTPUnauthorized() project_id = projects[0].id try: user = self.auth.get_user_from_access_key(key) except exception.NotFound: LOG.warn(_("User not found with provided API key.")) user = None if user and utils.strcmp_const_time(user.name, username): token_hash = hashlib.sha1('%s%s%f' % (username, key, time.time())).hexdigest() token_dict = {} token_dict['token_hash'] = token_hash token_dict['cdn_management_url'] = '' os_url = req.url.strip('/') os_url += '/' + project_id token_dict['server_management_url'] = os_url token_dict['storage_url'] = '' token_dict['user_id'] = user.id token = self.db.auth_token_create(ctxt, token_dict) return token, user elif user and user.name != username: msg = _("Provided API key is valid, but not for user " "'%(username)s'") % locals() LOG.warn(msg) return None, None
def test_strcmp_const_time(self): self.assertTrue(utils.strcmp_const_time('abc123', 'abc123')) self.assertFalse(utils.strcmp_const_time('a', 'aaaaa')) self.assertFalse(utils.strcmp_const_time('ABC123', 'abc123'))
def authenticate(self, access, signature, params, verb='GET', server_string='127.0.0.1:8773', path='/', check_type='ec2', headers=None): """Authenticates AWS request using access key and signature If the project is not specified, attempts to authenticate to a project with the same name as the user. This way, older tools that have no project knowledge will still work. :type access: str :param access: Access key for user in the form "access:project". :type signature: str :param signature: Signature of the request. :type params: list of str :param params: Web paramaters used for the signature. :type verb: str :param verb: Web request verb ('GET' or 'POST'). :type server_string: str :param server_string: Web request server string. :type path: str :param path: Web request path. :type check_type: str :param check_type: Type of signature to check. 'ec2' for EC2, 's3' for S3. Any other value will cause signature not to be checked. :type headers: list :param headers: HTTP headers passed with the request (only needed for s3 signature checks) :rtype: tuple (User, Project) :return: User and project that the request represents. """ # TODO(vish): check for valid timestamp (access_key, _sep, project_id) = access.partition(':') LOG.debug(_('Looking up user: %r'), access_key) user = self.get_user_from_access_key(access_key) LOG.debug('user: %r', user) if user is None: LOG.audit(_("Failed authorization for access key %s"), access_key) raise exception.AccessKeyNotFound(access_key=access_key) # NOTE(vish): if we stop using project name as id we need better # logic to find a default project for user if project_id == '': LOG.debug(_("Using project name = user name (%s)"), user.name) project_id = user.name project = self.get_project(project_id) if project is None: pjid = project_id uname = user.name LOG.audit(_("failed authorization: no project named %(pjid)s" " (user=%(uname)s)") % locals()) raise exception.ProjectNotFound(project_id=project_id) if not self.is_admin(user) and not self.is_project_member(user, project): uname = user.name uid = user.id pjname = project.name pjid = project.id LOG.audit(_("Failed authorization: user %(uname)s not admin" " and not member of project %(pjname)s") % locals()) raise exception.ProjectMembershipNotFound(project_id=pjid, user_id=uid) if check_type == 's3': sign = signer.Signer(user.secret.encode()) expected_signature = sign.s3_authorization(headers, verb, path) LOG.debug(_('user.secret: %s'), user.secret) LOG.debug(_('expected_signature: %s'), expected_signature) LOG.debug(_('signature: %s'), signature) if not utils.strcmp_const_time(signature, expected_signature): LOG.audit(_("Invalid signature for user %s"), user.name) raise exception.InvalidSignature(signature=signature, user=user) elif check_type == 'ec2': # NOTE(vish): hmac can't handle unicode, so encode ensures that # secret isn't unicode expected_signature = signer.Signer(user.secret.encode()).generate( params, verb, server_string, path) LOG.debug(_('user.secret: %s'), user.secret) LOG.debug(_('expected_signature: %s'), expected_signature) LOG.debug(_('signature: %s'), signature) if not utils.strcmp_const_time(signature, expected_signature): (addr_str, port_str) = utils.parse_server_string(server_string) # If the given server_string contains port num, try without it. if port_str != '': host_only_signature = signer.Signer( user.secret.encode()).generate(params, verb, addr_str, path) LOG.debug(_('host_only_signature: %s'), host_only_signature) if utils.strcmp_const_time(signature, host_only_signature): return (user, project) LOG.audit(_("Invalid signature for user %s"), user.name) raise exception.InvalidSignature(signature=signature, user=user) return (user, project)
def test_strcmp_const_time(self): self.assertTrue(utils.strcmp_const_time("abc123", "abc123")) self.assertFalse(utils.strcmp_const_time("a", "aaaaa")) self.assertFalse(utils.strcmp_const_time("ABC123", "abc123"))