예제 #1
0
    def create_request_token(self, context):
        headers = context['headers']
        oauth_headers = oauth1.get_oauth_headers(headers)
        consumer_id = oauth_headers.get('oauth_consumer_key')
        requested_project_id = headers.get('Requested-Project-Id')
        if not consumer_id:
            raise exception.ValidationError(
                attribute='oauth_consumer_key', target='request')
        if not requested_project_id:
            raise exception.ValidationError(
                attribute='requested_project_id', target='request')

        consumer_ref = self.oauth_api.get_consumer_with_secret(consumer_id)
        consumer = oauth1.Consumer(key=consumer_ref['id'],
                                   secret=consumer_ref['secret'])

        url = oauth1.rebuild_url(context['path'])
        oauth_request = oauth1.Request.from_request(
            http_method='POST',
            http_url=url,
            headers=context['headers'],
            query_string=context['query_string'],
            parameters={'requested_project_id': requested_project_id})
        oauth_server = oauth1.Server()
        oauth_server.add_signature_method(oauth1.SignatureMethod_HMAC_SHA1())
        params = oauth_server.verify_request(oauth_request,
                                             consumer,
                                             token=None)

        project_params = params['requested_project_id']
        if project_params != requested_project_id:
            msg = _('Non-oauth parameter - project, do not match')
            raise exception.Unauthorized(message=msg)

        request_token_duration = CONF.oauth1.request_token_duration
        token_ref = self.oauth_api.create_request_token(consumer_id,
                                                        requested_project_id,
                                                        request_token_duration)

        result = ('oauth_token=%(key)s&oauth_token_secret=%(secret)s'
                  % {'key': token_ref['id'],
                     'secret': token_ref['request_secret']})

        if CONF.oauth1.request_token_duration:
            expiry_bit = '&oauth_expires_at=%s' % token_ref['expires_at']
            result += expiry_bit

        headers = [('Content-Type', 'application/x-www-urlformencoded')]
        response = wsgi.render_response(result,
                                        status=(201, 'Created'),
                                        headers=headers)

        return response
예제 #2
0
    def create_request_token(self, context):
        headers = context['headers']
        oauth_headers = oauth1.get_oauth_headers(headers)
        consumer_id = oauth_headers.get('oauth_consumer_key')
        requested_project_id = headers.get('Requested-Project-Id')
        if not consumer_id:
            raise exception.ValidationError(
                attribute='oauth_consumer_key', target='request')
        if not requested_project_id:
            raise exception.ValidationError(
                attribute='requested_project_id', target='request')

        consumer_ref = self.oauth_api.get_consumer_with_secret(consumer_id)
        consumer = oauth1.Consumer(key=consumer_ref['id'],
                                   secret=consumer_ref['secret'])

        url = oauth1.rebuild_url(context['path'])
        oauth_request = oauth1.Request.from_request(
            http_method='POST',
            http_url=url,
            headers=context['headers'],
            query_string=context['query_string'],
            parameters={'requested_project_id': requested_project_id})
        oauth_server = oauth1.Server()
        oauth_server.add_signature_method(oauth1.SignatureMethod_HMAC_SHA1())
        params = oauth_server.verify_request(oauth_request,
                                             consumer,
                                             token=None)

        project_params = params['requested_project_id']
        if project_params != requested_project_id:
            msg = _('Non-oauth parameter - project, do not match')
            raise exception.Unauthorized(message=msg)

        request_token_duration = CONF.oauth1.request_token_duration
        token_ref = self.oauth_api.create_request_token(consumer_id,
                                                        requested_project_id,
                                                        request_token_duration)

        result = ('oauth_token=%(key)s&oauth_token_secret=%(secret)s'
                  % {'key': token_ref['id'],
                     'secret': token_ref['request_secret']})

        if CONF.oauth1.request_token_duration:
            expiry_bit = '&oauth_expires_at=%s' % token_ref['expires_at']
            result += expiry_bit

        headers = [('Content-Type', 'application/x-www-urlformencoded')]
        response = wsgi.render_response(result,
                                        status=(201, 'Created'),
                                        headers=headers)

        return response
예제 #3
0
    def create_request_token(self, context):
        headers = context['headers']
        oauth_headers = oauth1.get_oauth_headers(headers)
        consumer_id = oauth_headers.get('oauth_consumer_key')
        requested_project_id = headers.get('Requested-Project-Id')
        if not consumer_id:
            raise exception.ValidationError(
                attribute='oauth_consumer_key', target='request')
        if not requested_project_id:
            raise exception.ValidationError(
                attribute='requested_project_id', target='request')

        url = oauth1.rebuild_url(context['path'])

        req_headers = {'Requested-Project-Id': requested_project_id}
        req_headers.update(headers)
        request_verifier = oauth1.RequestTokenEndpoint(
            request_validator=validator.OAuthValidator(),
            token_generator=oauth1.token_generator)
        h, b, s = request_verifier.create_request_token_response(
            url,
            http_method='POST',
            body=context['query_string'],
            headers=req_headers)

        if (not b) or int(s) > 399:
            msg = _('Invalid signature')
            raise exception.Unauthorized(message=msg)

        request_token_duration = CONF.oauth1.request_token_duration
        token_ref = self.oauth_api.create_request_token(consumer_id,
                                                        requested_project_id,
                                                        request_token_duration)

        result = ('oauth_token=%(key)s&oauth_token_secret=%(secret)s'
                  % {'key': token_ref['id'],
                     'secret': token_ref['request_secret']})

        if CONF.oauth1.request_token_duration:
            expiry_bit = '&oauth_expires_at=%s' % token_ref['expires_at']
            result += expiry_bit

        headers = [('Content-Type', 'application/x-www-urlformencoded')]
        response = wsgi.render_response(result,
                                        status=(201, 'Created'),
                                        headers=headers)

        return response
예제 #4
0
    def authenticate(self, context, auth_info, auth_context):
        """Turn a signed request with an access key into a keystone token."""
        headers = context['headers']
        oauth_headers = oauth.get_oauth_headers(headers)
        consumer_id = oauth_headers.get('oauth_consumer_key')
        access_token_id = oauth_headers.get('oauth_token')

        if not access_token_id:
            raise exception.ValidationError(attribute='oauth_token',
                                            target='request')

        acc_token = self.oauth_api.get_access_token(access_token_id)
        consumer = self.oauth_api._get_consumer(consumer_id)

        expires_at = acc_token['expires_at']
        if expires_at:
            now = timeutils.utcnow()
            expires = timeutils.normalize_time(
                timeutils.parse_isotime(expires_at))
            if now > expires:
                raise exception.Unauthorized(_('Access token is expired'))

        consumer_obj = oauth1.Consumer(key=consumer['id'],
                                       secret=consumer['secret'])
        acc_token_obj = oauth1.Token(key=acc_token['id'],
                                     secret=acc_token['access_secret'])

        url = oauth.rebuild_url(context['path'])
        oauth_request = oauth1.Request.from_request(
            http_method='POST',
            http_url=url,
            headers=context['headers'],
            query_string=context['query_string'])
        oauth_server = oauth1.Server()
        oauth_server.add_signature_method(oauth1.SignatureMethod_HMAC_SHA1())
        params = oauth_server.verify_request(oauth_request,
                                             consumer_obj,
                                             token=acc_token_obj)

        if len(params) != 0:
            msg = _('There should not be any non-oauth parameters')
            raise exception.Unauthorized(message=msg)

        auth_context['user_id'] = acc_token['authorizing_user_id']
        auth_context['access_token_id'] = access_token_id
        auth_context['project_id'] = acc_token['project_id']
예제 #5
0
    def authenticate(self, context, auth_info, auth_context):
        """Turn a signed request with an access key into a keystone token."""
        headers = context['headers']
        oauth_headers = oauth.get_oauth_headers(headers)
        consumer_id = oauth_headers.get('oauth_consumer_key')
        access_token_id = oauth_headers.get('oauth_token')

        if not access_token_id:
            raise exception.ValidationError(
                attribute='oauth_token', target='request')

        acc_token = self.oauth_api.get_access_token(access_token_id)
        consumer = self.oauth_api.get_consumer_with_secret(consumer_id)

        expires_at = acc_token['expires_at']
        if expires_at:
            now = timeutils.utcnow()
            expires = timeutils.normalize_time(
                timeutils.parse_isotime(expires_at))
            if now > expires:
                raise exception.Unauthorized(_('Access token is expired'))

        consumer_obj = oauth1.Consumer(key=consumer['id'],
                                       secret=consumer['secret'])
        acc_token_obj = oauth1.Token(key=acc_token['id'],
                                     secret=acc_token['access_secret'])

        url = oauth.rebuild_url(context['path'])
        oauth_request = oauth1.Request.from_request(
            http_method='POST',
            http_url=url,
            headers=context['headers'],
            query_string=context['query_string'])
        oauth_server = oauth1.Server()
        oauth_server.add_signature_method(oauth1.SignatureMethod_HMAC_SHA1())
        params = oauth_server.verify_request(oauth_request,
                                             consumer_obj,
                                             token=acc_token_obj)

        if params:
            msg = _('There should not be any non-oauth parameters')
            raise exception.Unauthorized(message=msg)

        auth_context['user_id'] = acc_token['authorizing_user_id']
        auth_context['access_token_id'] = access_token_id
        auth_context['project_id'] = acc_token['project_id']
예제 #6
0
    def authenticate(self, context, auth_info, auth_context):
        """Turn a signed request with an access key into a keystone token."""
        headers = context['headers']
        oauth_headers = oauth.get_oauth_headers(headers)
        access_token_id = oauth_headers.get('oauth_token')

        if not access_token_id:
            raise exception.ValidationError(
                attribute='oauth_token', target='request')

        acc_token = self.oauth_api.get_access_token(access_token_id)

        expires_at = acc_token['expires_at']
        if expires_at:
            now = timeutils.utcnow()
            expires = timeutils.normalize_time(
                timeutils.parse_isotime(expires_at))
            if now > expires:
                raise exception.Unauthorized(_('Access token is expired'))

        url = oauth.rebuild_url(context['path'])
        access_verifier = oauth.ResourceEndpoint(
            request_validator=validator.OAuthValidator(),
            token_generator=oauth.token_generator)
        result, request = access_verifier.validate_protected_resource_request(
            url,
            http_method='POST',
            body=context['query_string'],
            headers=headers,
            realms=None
        )
        if not result:
            msg = _('Could not validate the access token')
            raise exception.Unauthorized(msg)
        auth_context['user_id'] = acc_token['authorizing_user_id']
        auth_context['access_token_id'] = access_token_id
        auth_context['project_id'] = acc_token['project_id']
예제 #7
0
    def create_access_token(self, context):
        headers = context['headers']
        oauth_headers = oauth1.get_oauth_headers(headers)
        consumer_id = oauth_headers.get('oauth_consumer_key')
        request_token_id = oauth_headers.get('oauth_token')
        oauth_verifier = oauth_headers.get('oauth_verifier')

        if not consumer_id:
            raise exception.ValidationError(
                attribute='oauth_consumer_key', target='request')
        if not request_token_id:
            raise exception.ValidationError(
                attribute='oauth_token', target='request')
        if not oauth_verifier:
            raise exception.ValidationError(
                attribute='oauth_verifier', target='request')

        req_token = self.oauth_api.get_request_token(
            request_token_id)

        expires_at = req_token['expires_at']
        if expires_at:
            now = timeutils.utcnow()
            expires = timeutils.normalize_time(
                timeutils.parse_isotime(expires_at))
            if now > expires:
                raise exception.Unauthorized(_('Request token is expired'))

        url = oauth1.rebuild_url(context['path'])

        access_verifier = oauth1.AccessTokenEndpoint(
            request_validator=validator.OAuthValidator(),
            token_generator=oauth1.token_generator)
        h, b, s = access_verifier.create_access_token_response(
            url,
            http_method='POST',
            body=context['query_string'],
            headers=headers)
        params = oauth1.extract_non_oauth_params(b)
        if len(params) != 0:
            msg = _('There should not be any non-oauth parameters')
            raise exception.Unauthorized(message=msg)

        if req_token['consumer_id'] != consumer_id:
            msg = _('provided consumer key does not match stored consumer key')
            raise exception.Unauthorized(message=msg)

        if req_token['verifier'] != oauth_verifier:
            msg = _('provided verifier does not match stored verifier')
            raise exception.Unauthorized(message=msg)

        if req_token['id'] != request_token_id:
            msg = _('provided request key does not match stored request key')
            raise exception.Unauthorized(message=msg)

        if not req_token.get('authorizing_user_id'):
            msg = _('Request Token does not have an authorizing user id')
            raise exception.Unauthorized(message=msg)

        access_token_duration = CONF.oauth1.access_token_duration
        token_ref = self.oauth_api.create_access_token(request_token_id,
                                                       access_token_duration)

        result = ('oauth_token=%(key)s&oauth_token_secret=%(secret)s'
                  % {'key': token_ref['id'],
                     'secret': token_ref['access_secret']})

        if CONF.oauth1.access_token_duration:
            expiry_bit = '&oauth_expires_at=%s' % (token_ref['expires_at'])
            result += expiry_bit

        headers = [('Content-Type', 'application/x-www-urlformencoded')]
        response = wsgi.render_response(result,
                                        status=(201, 'Created'),
                                        headers=headers)

        return response
예제 #8
0
    def create_access_token(self, context):
        headers = context['headers']
        oauth_headers = oauth1.get_oauth_headers(headers)
        consumer_id = oauth_headers.get('oauth_consumer_key')
        request_token_id = oauth_headers.get('oauth_token')
        oauth_verifier = oauth_headers.get('oauth_verifier')

        if not consumer_id:
            raise exception.ValidationError(attribute='oauth_consumer_key',
                                            target='request')
        if not request_token_id:
            raise exception.ValidationError(attribute='oauth_token',
                                            target='request')
        if not oauth_verifier:
            raise exception.ValidationError(attribute='oauth_verifier',
                                            target='request')

        consumer = self.oauth_api._get_consumer(consumer_id)
        req_token = self.oauth_api.get_request_token(request_token_id)

        expires_at = req_token['expires_at']
        if expires_at:
            now = timeutils.utcnow()
            expires = timeutils.normalize_time(
                timeutils.parse_isotime(expires_at))
            if now > expires:
                raise exception.Unauthorized(_('Request token is expired'))

        consumer_obj = oauth1.Consumer(key=consumer['id'],
                                       secret=consumer['secret'])
        req_token_obj = oauth1.Token(key=req_token['id'],
                                     secret=req_token['request_secret'])
        req_token_obj.set_verifier(oauth_verifier)

        url = oauth1.rebuild_url(context['path'])
        oauth_request = oauth1.Request.from_request(
            http_method='POST',
            http_url=url,
            headers=context['headers'],
            query_string=context['query_string'])
        oauth_server = oauth1.Server()
        oauth_server.add_signature_method(oauth1.SignatureMethod_HMAC_SHA1())
        params = oauth_server.verify_request(oauth_request,
                                             consumer_obj,
                                             token=req_token_obj)

        if len(params) != 0:
            msg = _('There should not be any non-oauth parameters')
            raise exception.Unauthorized(message=msg)

        if req_token['consumer_id'] != consumer_id:
            msg = _('provided consumer key does not match stored consumer key')
            raise exception.Unauthorized(message=msg)

        if req_token['verifier'] != oauth_verifier:
            msg = _('provided verifier does not match stored verifier')
            raise exception.Unauthorized(message=msg)

        if req_token['id'] != request_token_id:
            msg = _('provided request key does not match stored request key')
            raise exception.Unauthorized(message=msg)

        if not req_token.get('authorizing_user_id'):
            msg = _('Request Token does not have an authorizing user id')
            raise exception.Unauthorized(message=msg)

        access_token_duration = CONF.oauth1.access_token_duration
        token_ref = self.oauth_api.create_access_token(request_token_id,
                                                       access_token_duration)

        result = ('oauth_token=%(key)s&oauth_token_secret=%(secret)s' % {
            'key': token_ref['id'],
            'secret': token_ref['access_secret']
        })

        if CONF.oauth1.access_token_duration:
            expiry_bit = '&oauth_expires_at=%s' % (token_ref['expires_at'])
            result += expiry_bit

        headers = [('Content-Type', 'application/x-www-urlformencoded')]
        response = wsgi.render_response(result,
                                        status=(201, 'Created'),
                                        headers=headers)

        return response
예제 #9
0
    def create_request_token(self, context):
        headers = context['headers']
        oauth_headers = oauth1.get_oauth_headers(headers)
        consumer_id = oauth_headers.get('oauth_consumer_key')
        requested_role_ids = headers.get('Requested-Role-Ids')
        requested_project_id = headers.get('Requested-Project-Id')
        if not consumer_id:
            raise exception.ValidationError(attribute='oauth_consumer_key',
                                            target='request')
        if not requested_role_ids:
            raise exception.ValidationError(attribute='requested_role_ids',
                                            target='request')
        if not requested_project_id:
            raise exception.ValidationError(attribute='requested_project_id',
                                            target='request')

        req_role_ids = requested_role_ids.split(',')
        consumer_ref = self.oauth_api._get_consumer(consumer_id)
        consumer = oauth1.Consumer(key=consumer_ref['id'],
                                   secret=consumer_ref['secret'])

        url = oauth1.rebuild_url(context['path'])
        oauth_request = oauth1.Request.from_request(
            http_method='POST',
            http_url=url,
            headers=context['headers'],
            query_string=context['query_string'],
            parameters={
                'requested_role_ids': requested_role_ids,
                'requested_project_id': requested_project_id
            })
        oauth_server = oauth1.Server()
        oauth_server.add_signature_method(oauth1.SignatureMethod_HMAC_SHA1())
        params = oauth_server.verify_request(oauth_request,
                                             consumer,
                                             token=None)

        project_params = params['requested_project_id']
        if project_params != requested_project_id:
            msg = _('Non-oauth parameter - project, do not match')
            raise exception.Unauthorized(message=msg)

        roles_params = params['requested_role_ids']
        roles_params_list = roles_params.split(',')
        if roles_params_list != req_role_ids:
            msg = _('Non-oauth parameter - roles, do not match')
            raise exception.Unauthorized(message=msg)

        req_role_list = list()
        all_roles = self.identity_api.list_roles()
        for role in all_roles:
            for req_role in req_role_ids:
                if role['id'] == req_role:
                    req_role_list.append(role)

        if len(req_role_list) == 0:
            msg = _('could not find matching roles for provided role ids')
            raise exception.Unauthorized(message=msg)

        json_roles = jsonutils.dumps(req_role_list)
        request_token_duration = CONF.oauth1.request_token_duration
        token_ref = self.oauth_api.create_request_token(
            consumer_id, json_roles, requested_project_id,
            request_token_duration)

        result = ('oauth_token=%(key)s&oauth_token_secret=%(secret)s' % {
            'key': token_ref['id'],
            'secret': token_ref['request_secret']
        })

        if CONF.oauth1.request_token_duration:
            expiry_bit = '&oauth_expires_at=%s' % token_ref['expires_at']
            result += expiry_bit

        headers = [('Content-Type', 'application/x-www-urlformencoded')]
        response = wsgi.render_response(result,
                                        status=(201, 'Created'),
                                        headers=headers)

        return response
예제 #10
0
    def create_access_token(self, context):
        headers = context['headers']
        oauth_headers = oauth1.get_oauth_headers(headers)
        consumer_id = oauth_headers.get('oauth_consumer_key')
        request_token_id = oauth_headers.get('oauth_token')
        oauth_verifier = oauth_headers.get('oauth_verifier')

        if not consumer_id:
            raise exception.ValidationError(
                attribute='oauth_consumer_key', target='request')
        if not request_token_id:
            raise exception.ValidationError(
                attribute='oauth_token', target='request')
        if not oauth_verifier:
            raise exception.ValidationError(
                attribute='oauth_verifier', target='request')

        consumer = self.oauth_api.get_consumer_with_secret(consumer_id)
        req_token = self.oauth_api.get_request_token(
            request_token_id)

        expires_at = req_token['expires_at']
        if expires_at:
            now = timeutils.utcnow()
            expires = timeutils.normalize_time(
                timeutils.parse_isotime(expires_at))
            if now > expires:
                raise exception.Unauthorized(_('Request token is expired'))

        consumer_obj = oauth1.Consumer(key=consumer['id'],
                                       secret=consumer['secret'])
        req_token_obj = oauth1.Token(key=req_token['id'],
                                     secret=req_token['request_secret'])
        req_token_obj.set_verifier(oauth_verifier)

        url = oauth1.rebuild_url(context['path'])
        oauth_request = oauth1.Request.from_request(
            http_method='POST',
            http_url=url,
            headers=context['headers'],
            query_string=context['query_string'])
        oauth_server = oauth1.Server()
        oauth_server.add_signature_method(oauth1.SignatureMethod_HMAC_SHA1())
        params = oauth_server.verify_request(oauth_request,
                                             consumer_obj,
                                             token=req_token_obj)

        if params:
            msg = _('There should not be any non-oauth parameters')
            raise exception.Unauthorized(message=msg)

        if req_token['consumer_id'] != consumer_id:
            msg = _('provided consumer key does not match stored consumer key')
            raise exception.Unauthorized(message=msg)

        if req_token['verifier'] != oauth_verifier:
            msg = _('provided verifier does not match stored verifier')
            raise exception.Unauthorized(message=msg)

        if req_token['id'] != request_token_id:
            msg = _('provided request key does not match stored request key')
            raise exception.Unauthorized(message=msg)

        if not req_token.get('authorizing_user_id'):
            msg = _('Request Token does not have an authorizing user id')
            raise exception.Unauthorized(message=msg)

        access_token_duration = CONF.oauth1.access_token_duration
        token_ref = self.oauth_api.create_access_token(request_token_id,
                                                       access_token_duration)

        result = ('oauth_token=%(key)s&oauth_token_secret=%(secret)s'
                  % {'key': token_ref['id'],
                     'secret': token_ref['access_secret']})

        if CONF.oauth1.access_token_duration:
            expiry_bit = '&oauth_expires_at=%s' % (token_ref['expires_at'])
            result += expiry_bit

        headers = [('Content-Type', 'application/x-www-urlformencoded')]
        response = wsgi.render_response(result,
                                        status=(201, 'Created'),
                                        headers=headers)

        return response
예제 #11
0
    def create_request_token(self, context):
        headers = context['headers']
        oauth_headers = oauth1.get_oauth_headers(headers)
        consumer_id = oauth_headers.get('oauth_consumer_key')
        requested_role_ids = headers.get('Requested-Role-Ids')
        requested_project_id = headers.get('Requested-Project-Id')
        if not consumer_id:
            raise exception.ValidationError(
                attribute='oauth_consumer_key', target='request')
        if not requested_role_ids:
            raise exception.ValidationError(
                attribute='requested_role_ids', target='request')
        if not requested_project_id:
            raise exception.ValidationError(
                attribute='requested_project_id', target='request')

        req_role_ids = requested_role_ids.split(',')
        consumer_ref = self.oauth_api._get_consumer(consumer_id)
        consumer = oauth1.Consumer(key=consumer_ref['id'],
                                   secret=consumer_ref['secret'])

        url = oauth1.rebuild_url(context['path'])
        oauth_request = oauth1.Request.from_request(
            http_method='POST',
            http_url=url,
            headers=context['headers'],
            query_string=context['query_string'],
            parameters={'requested_role_ids': requested_role_ids,
                        'requested_project_id': requested_project_id})
        oauth_server = oauth1.Server()
        oauth_server.add_signature_method(oauth1.SignatureMethod_HMAC_SHA1())
        params = oauth_server.verify_request(oauth_request,
                                             consumer,
                                             token=None)

        project_params = params['requested_project_id']
        if project_params != requested_project_id:
            msg = _('Non-oauth parameter - project, do not match')
            raise exception.Unauthorized(message=msg)

        roles_params = params['requested_role_ids']
        roles_params_list = roles_params.split(',')
        if roles_params_list != req_role_ids:
            msg = _('Non-oauth parameter - roles, do not match')
            raise exception.Unauthorized(message=msg)

        req_role_list = list()
        all_roles = self.identity_api.list_roles()
        for role in all_roles:
            for req_role in req_role_ids:
                if role['id'] == req_role:
                    req_role_list.append(role)

        if len(req_role_list) == 0:
            msg = _('could not find matching roles for provided role ids')
            raise exception.Unauthorized(message=msg)

        json_roles = jsonutils.dumps(req_role_list)
        request_token_duration = CONF.oauth1.request_token_duration
        token_ref = self.oauth_api.create_request_token(consumer_id,
                                                        json_roles,
                                                        requested_project_id,
                                                        request_token_duration)

        result = ('oauth_token=%(key)s&oauth_token_secret=%(secret)s'
                  % {'key': token_ref['id'],
                     'secret': token_ref['request_secret']})

        if CONF.oauth1.request_token_duration:
            expiry_bit = '&oauth_expires_at=%s' % token_ref['expires_at']
            result += expiry_bit

        headers = [('Content-Type', 'application/x-www-urlformencoded')]
        response = wsgi.render_response(result,
                                        status=(201, 'Created'),
                                        headers=headers)

        return response