Пример #1
0
    def test_token_authorization(self):
        r"""Test how token_authorization behaves in GET and POST requests"""
        env = self._make_environ()
        p = token_authorization(engine=self.engine)
        session = p.manager.DBSession

        # First try an empty environment
        self.eval_unmet_predicate(p, env,
                                  'No valid matching OAuth token found')

        # Then try a non-existing token
        env['QUERY_STRING'] = urlencode(dict(oauth_token='some-token'))
        self.eval_unmet_predicate(p, env,
                                  'No valid matching OAuth token found')
        # There is no token in the environment
        self.assertFalse(env['repoze.what.oauth'].get('token'))

        # Now create a consumer and the token and try again
        consumer = Consumer(key='some-consumer', secret='some-secret')
        token = RequestToken.create(
            consumer,
            session=session,
            key='some-token',
            callback=u'http://www.test.com/some/path?x=1&y=%20a')
        session.add(consumer)
        session.flush()
        # This time we are passed through
        self.eval_met_predicate(p, env)

        # Environment now contains a token which was found according to the
        # query string parameters
        self.assertEquals(env['repoze.what.oauth']['token'], token)

        # Now construct a POST query and expect to find a callback function to
        # authorize the request token
        env = self._make_environ()
        env['REQUEST_METHOD'] = 'POST'
        self.eval_met_predicate(p, env)
        callback_maker = env['repoze.what.oauth']['make_callback']
        self.assertTrue(callback_maker)

        # We must provide a request token key and a userid to authorize a
        # request callback
        callback = callback_maker('some-token', u'some-user')
        self.assertEquals(len(callback['verifier']), 6)
        self.assertTrue(callback['verifier'] in callback['url'])

        # If the token callback url was provided as 'oob' (out of band) then the
        # callback['url'] should also specify oob
        token.callback = u'oob'
        callback = callback_maker('some-token', u'some-user')
        self.assertEquals(callback['url'], 'oob')
    def test_token_authorization(self):
        r"""Test how token_authorization behaves in GET and POST requests"""
        env = self._make_environ()
        p = token_authorization(engine=self.engine)
        session = p.manager.DBSession

        # First try an empty environment
        self.eval_unmet_predicate(p, env, 'No valid matching OAuth token found')

        # Then try a non-existing token
        env['QUERY_STRING'] = urlencode(dict(oauth_token='some-token'))
        self.eval_unmet_predicate(p, env, 'No valid matching OAuth token found')
        # There is no token in the environment
        self.assertFalse(env['repoze.what.oauth'].get('token'))

        # Now create a consumer and the token and try again
        consumer = Consumer(key='some-consumer', secret='some-secret')
        token = RequestToken.create(consumer, session=session,
            key='some-token',
            callback=u'http://www.test.com/some/path?x=1&y=%20a')
        session.add(consumer)
        session.flush()
        # This time we are passed through
        self.eval_met_predicate(p, env)

        # Environment now contains a token which was found according to the
        # query string parameters
        self.assertEquals(env['repoze.what.oauth']['token'], token)

        # Now construct a POST query and expect to find a callback function to
        # authorize the request token
        env = self._make_environ()
        env['REQUEST_METHOD'] = 'POST'
        self.eval_met_predicate(p, env)
        callback_maker = env['repoze.what.oauth']['make_callback']
        self.assertTrue(callback_maker)

        # We must provide a request token key and a userid to authorize a
        # request callback
        callback = callback_maker('some-token', u'some-user')
        self.assertEquals(len(callback['verifier']), 6)
        self.assertTrue(callback['verifier'] in callback['url'])

        # If the token callback url was provided as 'oob' (out of band) then the
        # callback['url'] should also specify oob
        token.callback = u'oob'
        callback = callback_maker('some-token', u'some-user')
        self.assertEquals(callback['url'], 'oob')
Пример #3
0
    def test_3_legged_flow(self):
        r"""Test a 2-legged flow end-to-end"""
        # The OAuth spec allows the access token to be the same as request
        # token. Let's try this here
        plugin = self._makeOne(access_token_path='/oauth/request_token')
        std_env_params = {
            'wsgi.url_scheme': 'http',
            'SERVER_NAME': 'www.example.com',
            'SERVER_PORT': '80',
            'REQUEST_METHOD': 'POST',
            'QUERY_STRING': '',
            'wsgi.input': '',
        }

        # Create one consumer in our DB
        from repoze.who.plugins.oauth.model import (Consumer, RequestToken,
                                                    AccessToken)
        self.session.add(Consumer(key='cons1', secret='secret1'))
        self.session.flush()

        # Construct a nice request token request and try to pass the
        # authenticator check. We do not have any tokens yet
        consumer = oauth2.Consumer('cons1', 'secret1')
        req = oauth2.Request.from_consumer_and_token(
            consumer=consumer,
            token=None,
            http_method='POST',
            http_url='http://www.example.com/oauth/request_token',
            parameters=dict(oauth_callback='http://test.com/?x=2'))
        req.sign_request(signature_method=oauth2.SignatureMethod_HMAC_SHA1(),
                         consumer=consumer,
                         token=None)

        # Pass the oauth parameters in the Authorization header
        env_params = {
            'HTTP_AUTHORIZATION': req.to_header()['Authorization'],
            'PATH_INFO': '/oauth/request_token',
        }
        env_params.update(std_env_params)
        environ = self._makeEnviron(env_params)
        identity = plugin.identify(environ)
        userid = plugin.authenticate(environ, identity)
        # While userid now contains the key of the consumer we don't care much
        # about it as the downstream application will never execute. What is
        # more important, `authenticate` replaced the downstream app with a
        # custom one.
        self.assertEquals(userid, 'consumer:%s' % consumer.key)
        app = environ['repoze.who.application']

        def assertUrlEncoded(code, headers, *args):
            self.assertEquals(
                dict(headers)['Content-Type'],
                'application/x-www-form-urlencoded')

        # The custom app will return a new request token for this consumer
        enc_token = ''.join(app(environ, assertUrlEncoded))
        # Decode the token
        dec_token = parse_qs(enc_token)
        # And create an oauth equivalent
        rtoken = oauth2.Token(key=dec_token['oauth_token'][0],
                              secret=dec_token['oauth_token_secret'][0])
        # Check token attributes
        # Autogenerated key and secret should be 40 chars long
        self.assertEquals(len(rtoken.key), 40)
        self.assertEquals(len(rtoken.secret), 40)
        # The plugin supports the updated OAuth specification
        self.assertEquals(dec_token['oauth_callback_confirmed'][0], 'true')
        # Such a token really exists
        dbtoken = plugin.manager.get_request_token(key=rtoken.key)
        self.assertEquals(dbtoken.secret, rtoken.secret)
        # And it really belongs to our consumer
        self.assertEquals(dbtoken.consumer.key, consumer.key)
        # And the callback url was set correctly
        self.assertEquals(dbtoken.callback, u'http://test.com/?x=2')

        # Now that we have the request token we should ask the user to authorize
        # it
        env_params = {}
        env_params.update(std_env_params)
        env_params.update({
            'REQUEST_METHOD':
            'GET',
            'PATH_INFO':
            '/oauth/authorize',
            'QUERY_STRING':
            urlencode(dict(oauth_token=rtoken.key))
        })
        environ = self._makeEnviron(env_params)
        # The token_authorization predicate is supposed to protect the token
        # authorization method
        from repoze.what.plugins.oauth import token_authorization
        authorizer = token_authorization(engine=self.engine)
        authorizer.check_authorization(environ)
        # environ now stores the same token taken from the DB. And we can use
        # the information associated with that token
        self.assertEquals(environ['repoze.what.oauth']['token'].key,
                          rtoken.key)
        self.assertEquals(environ['repoze.what.oauth']['token'].consumer.key,
                          consumer.key)

        # Suppose a user confirms that the consumer is legitimate and gives
        # permission to the user resources. Usually it will happen through a
        # form POSTed to 'authorize'. The predicate will intercept that and add
        # a method to environ which will mark the request token as validated and
        # create a verification key
        environ['REQUEST_METHOD'] = 'POST'
        authorizer.check_authorization(environ)
        # The request token validator method got added to the environ
        callback_maker = environ['repoze.what.oauth']['make_callback']
        # Call it providing the request token key and a userid - a callback dict
        # is returned
        callback = callback_maker(rtoken.key, u'some-user')
        # The autogenerated verifier should be 6 chars long
        self.assertEquals(len(callback['verifier']), 6)
        # And normally it is included in the callback url (except for
        # out-of-band callbacks)
        self.assertTrue(callback['verifier'] in callback['url'])
        # The request token is now attached to the userid
        self.assertEquals(environ['repoze.what.oauth']['token'].userid,
                          u'some-user')

        # Now that we have the request token verified we can convert it to an
        # access token
        # Set the token verifier - a wrong one first
        rtoken.set_verifier('-wrong-')
        # Create a new request using the new request token and verifier
        req = oauth2.Request.from_consumer_and_token(
            consumer=consumer,
            token=rtoken,
            http_method='POST',
            http_url='http://www.example.com/oauth/request_token')
        req.sign_request(signature_method=oauth2.SignatureMethod_HMAC_SHA1(),
                         consumer=consumer,
                         token=rtoken)

        env_params = {
            'HTTP_AUTHORIZATION': req.to_header()['Authorization'],
            # This url handles both request and access tokens
            'PATH_INFO': '/oauth/request_token',
        }
        env_params.update(std_env_params)
        environ = self._makeEnviron(env_params)
        # Force manager to reload all the objects as they might be out of date
        plugin.manager.DBSession.expire_all()
        # As we are providing a request token and a verifier we should get an
        # access token in exchange.
        identity = plugin.identify(environ)
        self.assertEquals(plugin.authenticate(environ, identity), None)

        # ... and we failed with the wrong verification code
        # Check that the plugin returned an Unauthorized response
        def start_401_response(code, *args):
            self.assertTrue(code.startswith('401'))

        environ['repoze.who.application'](environ, start_401_response)

        # Now create a request with the correct verifier
        rtoken.set_verifier(callback['verifier'])
        # Create a new request using the new request token and verifier
        req = oauth2.Request.from_consumer_and_token(
            consumer=consumer,
            token=rtoken,
            http_method='POST',
            http_url='http://www.example.com/oauth/request_token')
        req.sign_request(signature_method=oauth2.SignatureMethod_HMAC_SHA1(),
                         consumer=consumer,
                         token=rtoken)

        env_params = {
            'HTTP_AUTHORIZATION': req.to_header()['Authorization'],
            'PATH_INFO': '/oauth/request_token',
        }
        env_params.update(std_env_params)
        environ = self._makeEnviron(env_params)
        # As we are providing a request token and a verifier we should get an
        # access token in exchange
        identity = plugin.identify(environ)
        userid = plugin.authenticate(environ, identity)
        # The repoze.who.application now contains an app that will remove the
        # request token, create a new access token and return it as a parameter.
        # Let's call it and see.
        app = environ['repoze.who.application']
        enc_token = ''.join(app(environ, assertUrlEncoded))
        # Decode the access token
        dec_token = parse_qs(enc_token)
        # Create a local oauth equivalent of the access token
        atoken = oauth2.Token(key=dec_token['oauth_token'][0],
                              secret=dec_token['oauth_token_secret'][0])

        # If we repeat the request we get a 401 again
        identity = plugin.identify(environ)
        self.assertEquals(plugin.authenticate(environ, identity), None)
        environ['repoze.who.application'](environ, start_401_response)

        # So now we have a valid access token. Let's try an authorized request
        req = oauth2.Request.from_consumer_and_token(
            consumer=consumer,
            token=atoken,
            http_method='GET',
            http_url='http://www.example.com/app')
        req.sign_request(signature_method=oauth2.SignatureMethod_HMAC_SHA1(),
                         consumer=consumer,
                         token=atoken)

        env_params = {
            'HTTP_AUTHORIZATION': req.to_header()['Authorization'],
            'PATH_INFO': '/app',
        }
        env_params.update(std_env_params)
        env_params['REQUEST_METHOD'] = 'GET'
        environ = self._makeEnviron(env_params)
        identity = plugin.identify(environ)
        userid = plugin.authenticate(environ, identity)
        # We got a *user* id
        self.assertEquals(userid, 'some-user')
        # Identity also contains the consumer and consumer key
        self.assertEquals(identity['repoze.who.consumerkey'], consumer.key)
        # And we're good to go with the downstream app
        self.assertEquals(environ.get('repoze.who.application'), None)

        # Cleanup consumers
        self.session.execute(Consumer.__table__.delete())
Пример #4
0
    def test_3_legged_flow(self):
        r"""Test a 2-legged flow end-to-end"""
        # The OAuth spec allows the access token to be the same as request
        # token. Let's try this here
        plugin = self._makeOne(access_token_path='/oauth/request_token')
        std_env_params = {
            'wsgi.url_scheme': 'http',
            'SERVER_NAME': 'www.example.com',
            'SERVER_PORT': '80',
            'REQUEST_METHOD': 'POST',
            'QUERY_STRING': '',
            'wsgi.input': '',
        }

        # Create one consumer in our DB
        from repoze.who.plugins.oauth.model import (Consumer, RequestToken,
            AccessToken)
        self.session.add(Consumer(key='cons1', secret='secret1'))
        self.session.flush()

        # Construct a nice request token request and try to pass the
        # authenticator check. We do not have any tokens yet
        consumer = oauth2.Consumer('cons1', 'secret1')
        req = oauth2.Request.from_consumer_and_token(
            consumer=consumer,
            token=None,
            http_method='POST',
            http_url='http://www.example.com/oauth/request_token',
            parameters=dict(oauth_callback='http://test.com/?x=2'))
        req.sign_request(signature_method=oauth2.SignatureMethod_HMAC_SHA1(),
            consumer=consumer, token=None)

        # Pass the oauth parameters in the Authorization header
        env_params = {
            'HTTP_AUTHORIZATION': req.to_header()['Authorization'],
            'PATH_INFO': '/oauth/request_token',
        }
        env_params.update(std_env_params)
        environ = self._makeEnviron(env_params)
        identity = plugin.identify(environ)
        userid = plugin.authenticate(environ, identity)
        # While userid now contains the key of the consumer we don't care much
        # about it as the downstream application will never execute. What is
        # more important, `authenticate` replaced the downstream app with a
        # custom one.
        self.assertEquals(userid, 'consumer:%s' % consumer.key)
        app = environ['repoze.who.application']
        def assertUrlEncoded(code, headers, *args):
            self.assertEquals(dict(headers)['Content-Type'],
                'application/x-www-form-urlencoded')
        # The custom app will return a new request token for this consumer
        enc_token = ''.join(app(environ, assertUrlEncoded))
        # Decode the token
        dec_token = parse_qs(enc_token)
        # And create an oauth equivalent
        rtoken = oauth2.Token(key=dec_token['oauth_token'][0],
            secret=dec_token['oauth_token_secret'][0])
        # Check token attributes
        # Autogenerated key and secret should be 40 chars long
        self.assertEquals(len(rtoken.key), 40)
        self.assertEquals(len(rtoken.secret), 40)
        # The plugin supports the updated OAuth specification
        self.assertEquals(dec_token['oauth_callback_confirmed'][0], 'true')
        # Such a token really exists
        dbtoken = plugin.manager.get_request_token(key=rtoken.key)
        self.assertEquals(dbtoken.secret, rtoken.secret)
        # And it really belongs to our consumer
        self.assertEquals(dbtoken.consumer.key, consumer.key)
        # And the callback url was set correctly
        self.assertEquals(dbtoken.callback, u'http://test.com/?x=2')

        # Now that we have the request token we should ask the user to authorize
        # it
        env_params = {}
        env_params.update(std_env_params)
        env_params.update({
            'REQUEST_METHOD': 'GET',
            'PATH_INFO': '/oauth/authorize',
            'QUERY_STRING': urlencode(dict(oauth_token=rtoken.key))
        })
        environ = self._makeEnviron(env_params)
        # The token_authorization predicate is supposed to protect the token
        # authorization method
        from repoze.what.plugins.oauth import token_authorization
        authorizer = token_authorization(engine=self.engine)
        authorizer.check_authorization(environ)
        # environ now stores the same token taken from the DB. And we can use
        # the information associated with that token
        self.assertEquals(environ['repoze.what.oauth']['token'].key, rtoken.key)
        self.assertEquals(environ['repoze.what.oauth']['token'].consumer.key,
            consumer.key)

        # Suppose a user confirms that the consumer is legitimate and gives
        # permission to the user resources. Usually it will happen through a
        # form POSTed to 'authorize'. The predicate will intercept that and add
        # a method to environ which will mark the request token as validated and
        # create a verification key
        environ['REQUEST_METHOD'] = 'POST'
        authorizer.check_authorization(environ)
        # The request token validator method got added to the environ
        callback_maker = environ['repoze.what.oauth']['make_callback']
        # Call it providing the request token key and a userid - a callback dict
        # is returned
        callback = callback_maker(rtoken.key, u'some-user')
        # The autogenerated verifier should be 6 chars long
        self.assertEquals(len(callback['verifier']), 6)
        # And normally it is included in the callback url (except for
        # out-of-band callbacks)
        self.assertTrue(callback['verifier'] in callback['url'])
        # The request token is now attached to the userid
        self.assertEquals(environ['repoze.what.oauth']['token'].userid,
            u'some-user')

        # Now that we have the request token verified we can convert it to an
        # access token
        # Set the token verifier - a wrong one first
        rtoken.set_verifier('-wrong-')
        # Create a new request using the new request token and verifier
        req = oauth2.Request.from_consumer_and_token(
            consumer=consumer,
            token=rtoken,
            http_method='POST',
            http_url='http://www.example.com/oauth/request_token')
        req.sign_request(signature_method=oauth2.SignatureMethod_HMAC_SHA1(),
            consumer=consumer, token=rtoken)

        env_params = {
            'HTTP_AUTHORIZATION': req.to_header()['Authorization'],
            # This url handles both request and access tokens
            'PATH_INFO': '/oauth/request_token',
        }
        env_params.update(std_env_params)
        environ = self._makeEnviron(env_params)
        # Force manager to reload all the objects as they might be out of date
        plugin.manager.DBSession.expire_all()
        # As we are providing a request token and a verifier we should get an
        # access token in exchange.
        identity = plugin.identify(environ)
        self.assertEquals(plugin.authenticate(environ, identity), None)

        # ... and we failed with the wrong verification code
        # Check that the plugin returned an Unauthorized response
        def start_401_response(code, *args):
            self.assertTrue(code.startswith('401'))
        environ['repoze.who.application'](environ, start_401_response)

        # Now create a request with the correct verifier
        rtoken.set_verifier(callback['verifier'])
        # Create a new request using the new request token and verifier
        req = oauth2.Request.from_consumer_and_token(
            consumer=consumer,
            token=rtoken,
            http_method='POST',
            http_url='http://www.example.com/oauth/request_token')
        req.sign_request(signature_method=oauth2.SignatureMethod_HMAC_SHA1(),
            consumer=consumer, token=rtoken)

        env_params = {
            'HTTP_AUTHORIZATION': req.to_header()['Authorization'],
            'PATH_INFO': '/oauth/request_token',
        }
        env_params.update(std_env_params)
        environ = self._makeEnviron(env_params)
        # As we are providing a request token and a verifier we should get an
        # access token in exchange
        identity = plugin.identify(environ)
        userid = plugin.authenticate(environ, identity)
        # The repoze.who.application now contains an app that will remove the
        # request token, create a new access token and return it as a parameter.
        # Let's call it and see.
        app = environ['repoze.who.application']
        enc_token = ''.join(app(environ, assertUrlEncoded))
        # Decode the access token
        dec_token = parse_qs(enc_token)
        # Create a local oauth equivalent of the access token
        atoken = oauth2.Token(key=dec_token['oauth_token'][0],
            secret=dec_token['oauth_token_secret'][0])

        # If we repeat the request we get a 401 again
        identity = plugin.identify(environ)
        self.assertEquals(plugin.authenticate(environ, identity), None)
        environ['repoze.who.application'](environ, start_401_response)

        # So now we have a valid access token. Let's try an authorized request
        req = oauth2.Request.from_consumer_and_token(
            consumer=consumer,
            token=atoken,
            http_method='GET',
            http_url='http://www.example.com/app')
        req.sign_request(signature_method=oauth2.SignatureMethod_HMAC_SHA1(),
            consumer=consumer, token=atoken)

        env_params = {
            'HTTP_AUTHORIZATION': req.to_header()['Authorization'],
            'PATH_INFO': '/app',
        }
        env_params.update(std_env_params)
        env_params['REQUEST_METHOD'] = 'GET'
        environ = self._makeEnviron(env_params)
        identity = plugin.identify(environ)
        userid = plugin.authenticate(environ, identity)
        # We got a *user* id
        self.assertEquals(userid, 'some-user')
        # Identity also contains the consumer and consumer key
        self.assertEquals(identity['repoze.who.consumerkey'], consumer.key)
        # And we're good to go with the downstream app
        self.assertEquals(environ.get('repoze.who.application'), None)

        # Cleanup consumers
        self.session.execute(Consumer.__table__.delete())