Esempio n. 1
0
    def setUp(self):
        jane = User.objects.create_user('jane', '*****@*****.**', 'toto')

        self.resource = Resource(name='photos', url='/oauth/photo/')
        self.resource.save()
        self.CONSUMER_KEY = 'dpf43f3p2l4k3l03'
        self.CONSUMER_SECRET = 'kd94hf93k423kf44'
        self.consumer = Consumer(key=self.CONSUMER_KEY,
                                 secret=self.CONSUMER_SECRET,
                                 name='printer.example.com',
                                 user=jane)
        self.consumer.save()
Esempio n. 2
0
def create_consumer():
    ConsumerInfo.objects.filter(consumer__key=KEY).delete()
    Consumer.objects.filter(key=KEY).delete()

    c = Consumer(name='Example Consumer', description='Consumer to do some demos with', status=ACCEPTED,
                 user=User.objects.get(username='******'), xauth_allowed=False,
                 key=KEY, secret=SECRET)
    #c.generate_random_codes()
    c.save()
    i = ConsumerInfo(consumer=c)
    i.admin_contact = '*****@*****.**'
    i.permissions = ['courses', 'grades']
    i.save()
    return c
Esempio n. 3
0
def setup_func():
    
    #from http://code.google.com/p/nose-gae/issues/detail?id=13
    os.environ['SERVER_NAME'] = 'localhost'
    os.environ['SERVER_PORT'] = '8080'
    os.environ['AUTH_DOMAIN'] = 'example.org'
    os.environ['USER_EMAIL'] = ''
    os.environ['USER_ID'] = ''
    
    
    resource = Resource(name='default', url='/oauth/photo/')
    resource.put()
    
    consumer = Consumer(key_=CONSUMER_KEY, secret=CONSUMER_SECRET, name='printer.example.com')
    consumer.put()
        def setUp(self):
            self.client = Client()
            self.username = '******'
            self.email = '*****@*****.**'
            self.password = '******'
            self.user = User.objects.create_user(self.username, self.email, self.password)

            # OAuth requirements
            self.resource = Resource(name='data', url='/')
            self.resource.save()
            self.CONSUMER_KEY = 'dpf43f3p2l4k3l03'
            self.CONSUMER_SECRET = 'kd94hf93k423kf44'
            self.consumer = Consumer(key=self.CONSUMER_KEY, secret=self.CONSUMER_SECRET,
                                name='api.example.com', user=self.user)
            self.consumer.save()
Esempio n. 5
0
def setup_func():

    #from http://code.google.com/p/nose-gae/issues/detail?id=13
    os.environ['SERVER_NAME'] = 'localhost'
    os.environ['SERVER_PORT'] = '8080'
    os.environ['AUTH_DOMAIN'] = 'example.org'
    os.environ['USER_EMAIL'] = ''
    os.environ['USER_ID'] = ''

    resource = Resource(name='default', url='/oauth/photo/')
    resource.put()

    consumer = Consumer(key_=CONSUMER_KEY,
                        secret=CONSUMER_SECRET,
                        name='printer.example.com')
    consumer.put()
Esempio n. 6
0
    def setUp(self):
        username = self.username = '******'
        password = self.password = '******'
        email = self.email = '*****@*****.**'
        jane = self.jane = User.objects.create_user(username, email, password)
        resource = self.resource = Resource(name='photos', url='/api/v1/user/jane/')
        resource.save()
        CONSUMER_KEY = self.CONSUMER_KEY = 'dpf43f3p2l4k3l03'
        CONSUMER_SECRET = self.CONSUMER_SECRET = 'kd94hf93k423kf44'
        consumer = self.consumer = Consumer(key=CONSUMER_KEY, secret=CONSUMER_SECRET,
                                            name='printer.example.com', user=jane)
        consumer.save()

        self.callback_token = self.callback = 'http://printer.example.com/request_token_ready'
        self.callback_confirmed = True
        self.request_token_parameters = {
            'oauth_consumer_key': self.CONSUMER_KEY,
            'oauth_signature_method': 'PLAINTEXT',
            'oauth_signature': '%s&' % self.CONSUMER_SECRET,
            'oauth_timestamp': str(int(time.time())),
            'oauth_nonce': 'requestnonce',
            'oauth_version': '1.0',
            'oauth_callback': self.callback,
            'scope': 'photos',  # custom argument to specify Protected Resource
            }

        self.c = Client()
Esempio n. 7
0
    def setUp(self):
        self.faketime = 525942870
        self.client = Client()

        # create a Consumer (and associated stuff)
        try:
            u = User.objects.get(username='******')
        except User.DoesNotExist:
            u = User(username='******')
            u.save()

        try:
            c = Consumer.objects.get(name='Test Consumer')
        except Consumer.DoesNotExist:
            c = Consumer(name='Test Consumer')

        c.description = 'Consumer to do some tests with'
        c.status = ACCEPTED
        c.user = u
        c.xauth_allowed = False
        c.generate_random_codes()
        c.save()
        self.consumer = c

        i = ConsumerInfo(consumer=c)
        i.admin_contact = '*****@*****.**'
        i.permissions = ['courses']
        i.timestamp = self.faketime - 10  # make sure the ConsumerInfo was there "before" the Token was created
        i.save()
        self.consumerinfo = i

        # create an access token so we can jump in to requests
        try:
            t = Token.objects.get(token_type=Token.ACCESS, consumer=c, user=u)
        except Token.DoesNotExist:
            t = Token(token_type=Token.ACCESS,
                      consumer=c,
                      user=u,
                      timestamp=self.faketime)

        t.is_approved = True
        t.generate_random_codes()
        t.verifier = VERIFIER
        t.save()
        self.token = t
def create_consumer():
    ConsumerInfo.objects.filter(consumer__key=KEY).delete()
    Consumer.objects.filter(key=KEY).delete()

    c = Consumer(name='Example Consumer',
                 description='Consumer to do some demos with',
                 status=ACCEPTED,
                 user=User.objects.get(username='******'),
                 xauth_allowed=False,
                 key=KEY,
                 secret=SECRET)
    #c.generate_random_codes()
    c.save()
    i = ConsumerInfo(consumer=c)
    i.admin_contact = '*****@*****.**'
    i.permissions = ['courses', 'grades']
    i.save()
    return c
Esempio n. 9
0
    def setUp(self):
        jane = User.objects.create_user("jane", "*****@*****.**", "toto")

        self.resource = Resource(name="photos", url="/oauth/photo/")
        self.resource.save()
        self.CONSUMER_KEY = "dpf43f3p2l4k3l03"
        self.CONSUMER_SECRET = "kd94hf93k423kf44"
        self.consumer = Consumer(
            key=self.CONSUMER_KEY, secret=self.CONSUMER_SECRET, name="printer.example.com", user=jane
        )
        self.consumer.save()
Esempio n. 10
0
def create_consumer(name, description, owner_userid, admin_contact, permissions):
    """
    Create a new Consumer with all of the info we need recorded. Arguments: (name, description, owner_userid, admin_contact, permissions)

    Could be rolled into a form+view in /sysadmin/, but how many could there possibly be?
    """
    assert set(permissions) <= set(PERMISSION_OPTIONS.keys()), 'Permissions must be chosen from PERMISSION_CHOICES.'

    User = get_user_model()
    c = Consumer(name=name, description=description, status=ACCEPTED,
            user=User.objects.get(username=owner_userid), xauth_allowed=False)
    c.generate_random_codes()
    c.save()

    i = ConsumerInfo(consumer=c)
    i.admin_contact = admin_contact
    i.permissions = list(permissions)
    i.save()

    print("Consumer key:", c.key)
    print("Consumer secret:", c.secret)
Esempio n. 11
0
def create_consumer(name, description, owner_userid, admin_contact,
                    permissions):
    """
    Create a new Consumer with all of the info we need recorded. Arguments: (name, description, owner_userid, admin_contact, permissions)

    Could be rolled into a form+view in /sysadmin/, but how many could there possibly be?
    """
    assert set(permissions) <= set(PERMISSION_OPTIONS.keys(
    )), 'Permissions must be chosen from PERMISSION_CHOICES.'

    User = get_user_model()
    c = Consumer(name=name,
                 description=description,
                 status=ACCEPTED,
                 user=User.objects.get(username=owner_userid),
                 xauth_allowed=False)
    c.generate_random_codes()
    c.save()

    i = ConsumerInfo(consumer=c)
    i.admin_contact = admin_contact
    i.permissions = list(permissions)
    i.save()

    print("Consumer key:", c.key)
    print("Consumer secret:", c.secret)
Esempio n. 12
0
    def setUp(self):
        self.faketime = 525942870
        self.client = Client()

        # create a Consumer (and associated stuff)
        try:
            u = User.objects.get(username='******')
        except User.DoesNotExist:
            u = User(username='******')
            u.save()

        try:
            c = Consumer.objects.get(name='Test Consumer')
        except Consumer.DoesNotExist:
            c = Consumer(name='Test Consumer')

        c.description = 'Consumer to do some tests with'
        c.status = ACCEPTED
        c.user = u
        c.xauth_allowed = False
        c.generate_random_codes()
        c.save()
        self.consumer = c

        i = ConsumerInfo(consumer=c)
        i.admin_contact = '*****@*****.**'
        i.permissions = ['courses']
        i.timestamp = self.faketime - 10 # make sure the ConsumerInfo was there "before" the Token was created
        i.save()
        self.consumerinfo = i

        # create an access token so we can jump in to requests
        try:
            t = Token.objects.get(token_type=Token.ACCESS, consumer=c, user=u)
        except Token.DoesNotExist:
            t = Token(token_type=Token.ACCESS, consumer=c, user=u, timestamp=self.faketime)
       
        t.is_approved = True
        t.generate_random_codes()
        t.verifier = VERIFIER
        t.save()
        self.token = t
        def setUp(self):
            self.client = Client()
            self.username = '******'
            self.email = '*****@*****.**'
            self.password = '******'
            self.user = User.objects.create_user(self.username, self.email, self.password)

            # OAuth requirements
            self.resource = Resource(name='data', url='/')
            self.resource.save()
            self.CONSUMER_KEY = 'dpf43f3p2l4k3l03'
            self.CONSUMER_SECRET = 'kd94hf93k423kf44'
            self.consumer = Consumer(key=self.CONSUMER_KEY, secret=self.CONSUMER_SECRET,
                                name='api.example.com', user=self.user)
            self.consumer.save()
        def setUp(self):
            self.client = Client()
            self.username = "******"
            self.email = "*****@*****.**"
            self.password = "******"
            self.user = User.objects.create_user(self.username, self.email, self.password)

            # OAuth requirements
            self.resource = Resource(name="data", url="/")
            self.resource.save()
            self.CONSUMER_KEY = "dpf43f3p2l4k3l03"
            self.CONSUMER_SECRET = "kd94hf93k423kf44"
            self.consumer = Consumer(
                key=self.CONSUMER_KEY, secret=self.CONSUMER_SECRET, name="api.example.com", user=self.user
            )
            self.consumer.save()
Esempio n. 15
0
    def setUp(self):
        self.username = '******'
        self.password = '******'
        self.email = '*****@*****.**'
        self.jane = User.objects.create_user(self.username, self.email, self.password)
        self.scope = Scope.objects.create(name='photos', url='/oauth/photo/')

        self.CONSUMER_KEY = 'dpf43f3p2l4k3l03'
        self.CONSUMER_SECRET = 'kd94hf93k423kf44'

        consumer = self.consumer = Consumer(key=self.CONSUMER_KEY, secret=self.CONSUMER_SECRET,
            name='printer.example.com', user=self.jane)
        consumer.save()

        self.callback_token = self.callback = 'http://printer.example.com/request_token_ready'
        self.callback_confirmed = True
        self.c = Client()
Esempio n. 16
0
from oauth_provider.models import Resource,Consumer
from oauth_provider.consts import ACCEPTED



default_consumer = Consumer(name="Tomboy default consumer", 
        description="Tomboy default consumer", 
        key_ = 'anyone',
        secret = 'anyone',
        status = ACCEPTED
        )
default_consumer.put()

default_resource = Resource(name="default")
default_resource.put()
Esempio n. 17
0
def test_oauth1_0():
    """
    Test to veriy OAuth 1.0 flow
    """

    """
    After Jane informs printer.example.com that she would like to print her 
    vacation photo stored at photos.example.net, the printer website tries to 
    access the photo and receives HTTP 401 Unauthorized indicating it is private. 
    The Service Provider includes the following header with the response::
    """
    
    #TODO - not able to handle /request_token/ - returns 404
    #TODO - add test for reuse of nonce for the request token stage?
    #TODO - add test for oauth params in Authorization, GET and POST
    response = app.get('/request_token',status=401)
    assert response.status == '401 Invalid request parameters.'
    assert response.headers['WWW-Authenticate'] == 'OAuth realm="http://events.example.net/"'
    assert response.body == 'Invalid request parameters.'
    
    """
    The Consumer sends the following HTTP POST request to the Service Provider::
    """
    import time
    parameters = {
        'oauth_consumer_key': CONSUMER_KEY,
        'oauth_signature_method': 'PLAINTEXT',
        'oauth_signature': '%s&' % CONSUMER_SECRET,
        'oauth_timestamp': str(int(time.time())),
        'oauth_nonce': 'requestnonce',
        'oauth_version': '1.0',
        #'scope': 'default', # custom argument to specify Protected Resource
    }
    
    response = app.post('/request_token',parameters) 
    
    """
    The Service Provider checks the signature and replies with an unauthorized 
    Request Token in the body of the HTTP response::
    """
    assert response.status == '200 OK'
    
    tokens = Token.all().fetch(1000)
    #double checking the sanity of the test - there should only be one token in 
    #the store at this stage
    
    assert len(tokens) == 1
    token = tokens[0]
    assert 'oauth_token_secret=%s&oauth_token=%s'%(token.secret,token.key_) == response.body
    
    #Ensure that the token returned is unauthorized request token
    assert token.is_approved == False
    assert token.token_type == Token.REQUEST
    
    """
    If you try to access a resource with a wrong scope, it will return an error::
    """

    #the scope related tests are not here as they the scope
    #function has not been implemented yet
    #>> parameters['scope'] = 'videos'
    #>>> response = c.get("/oauth/request_token/", parameters)
    #>>> response.status_code
    #401
    #>>> response.content
    #'Resource videos does not exist.'
    
    
    """
    Requesting User Authorization
    -----------------------------
    
    The Consumer redirects Jane's browser to the Service Provider User 
    Authorization URL to obtain Jane's approval for accessing her private photos.
    
    The Service Provider asks Jane to sign-in using her username and password::
    
    """
    parameters = {
        'oauth_token' : token.key_,
        'oauth_callback' : 'http://test.com/request_token_ready'
    }
    
    response = app.post('/authorize', parameters)
    assert response.status == '302 Moved Temporarily'
    assert response.location ==\
'http://localhost/_ah/login?continue=http%%3A//localhost/authorize%%3Foauth_token%%3D%s%%26oauth_callback%%3Dhttp%%3A//test.com/request_token_ready'%(token.key_)

    #the token details should not be altered by this call
    tokens = Token.all().fetch(1000)
    assert len(tokens) == 1
    token = tokens[0]
    
    assert token.is_approved == False
    assert token.token_type == Token.REQUEST
    
    #In reality the user would of been redirected to the Google login page and 
    #then redirected to the authorization url. We simulate the user being logged
    #in and redirect manually to the authorization page
    
    #simulate logged in 
    os.environ['USER_EMAIL'] = '*****@*****.**'
    
    response = app.post('/authorize', parameters)
    
    #verify that the request token is now approved
    tokens = Token.all().fetch(1000)
    assert len(tokens) == 1
    token = tokens[0]
    
    assert token.is_approved == True
    assert token.token_type == Token.REQUEST
    
    #verify the response - now that we are approved we should get 
    assert response.status == '302 Moved Temporarily'
    assert response.location == 'http://test.com/request_token_ready?oauth_token=%s'%(token.key_)
    
    #TODO add test for case where the user rejects the approval, 
    #now the flow assumes that it will always be approved upon logging in
    
    """
    Obtaining an Access Token
    -------------------------
    
    Now that the Consumer knows Jane approved the Request Token, it asks the 
    Service Provider to exchange it for an Access Token::
    """
    
    parameters = {
         'oauth_consumer_key': CONSUMER_KEY,
         'oauth_token': token.key_,
         'oauth_signature_method': 'PLAINTEXT',
         'oauth_signature': '%s&%s' % (CONSUMER_SECRET, token.secret),
         'oauth_timestamp': str(int(time.time())),
         'oauth_nonce': 'accessnonce',
         'oauth_version': '1.0',
    }
    response = app.post("/access_token", parameters)
    
    """
    The Service Provider checks the signature and replies with an Access Token in 
    the body of the HTTP response::
    """
    
    response.status == '200 OK'
    #verify the access token now 
    
    access_tokens = Token.all()\
        .filter('token_type =',Token.ACCESS).fetch(1000)
    #double checking the sanity of the test - there should only be one token in 
    #the store at this stage
    
    assert len(access_tokens) == 1
    access_token = access_tokens[0]
    assert 'oauth_token_secret=%s&oauth_token=%s'%(access_token.secret,access_token.key_) == response.body

    assert str(access_token.user) == '*****@*****.**'
    
    """
    The Consumer will not be able to request another Access Token with the same
    Nonce::
    """
    
    nonces = Nonce.all().fetch(1000)
    assert nonces[0].key_ == "accessnonce"
    
    response = app.post("/access_token", parameters,status=401)
    
    assert response.status == '401 Nonce already used: accessnonce'
    assert response.body == 'Nonce already used: accessnonce'
    
    """
    The Consumer will not be able to request an Access Token if the token is not
    approved::
    """
    
    token.is_approved = False
    token.put()
    
    parameters['oauth_nonce'] = 'anotheraccessnonce'
    response = app.post("/access_token", parameters,status=401)
    response.status == "401 Consumer key or token key does not match. Make sure your request token is approved. Check your verifier too if you use OAuth 1.0a."
    response.body == 'Consumer key or token key does not match. Make sure your request token is approved. Check your verifier too if you use OAuth 1.0a.'
    
    """
    Accessing Protected Resources
    -----------------------------
    
    The Consumer is now ready to request the private photo. Since the photo URL is 
    not secure (HTTP), it must use HMAC-SHA1.
    
    Generating Signature Base String
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    To generate the signature, it first needs to generate the Signature Base 
    String. The request contains the following parameters (oauth_signature 
    excluded) which are ordered and concatenated into a normalized string::
    """
    
    parameters = {
         'oauth_consumer_key': CONSUMER_KEY,
         'oauth_token': access_token.key_,
         'oauth_signature_method': 'HMAC-SHA1',
         'oauth_timestamp': str(int(time.time())),
         'oauth_nonce': 'accessresourcenonce',
         'oauth_version': '1.0',
    }
    
    """
    Calculating Signature Value
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    HMAC-SHA1 produces the following digest value as a base64-encoded string 
    (using the Signature Base String as text and kd94hf93k423kf44&pfkkdhi9sl3r4s00 
    as key)::
    """
    
    consumer = Consumer.all().fetch(1000)[0]
    
    #we dont use the OAuthRequest.from_token_and_callback function as how the 
    #original method does as it does a token.key instead of token.key_
    
    oauth_request = OAuthRequest('POST','http://localhost/protected',parameters)
    signature_method = OAuthSignatureMethod_HMAC_SHA1()
    signature = signature_method.build_signature(oauth_request, consumer, 
                                                         access_token)
    

    
    """
    Requesting Protected Resource
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    All together, the Consumer request for the photo is::
    """

    parameters['oauth_signature'] = signature
    response = app.post("/protected", parameters)
    
    assert response.status == '200 OK'
    assert response.body == 'Protected Resource access!'
    
    """
    Otherwise, an explicit error will be raised::
    """
    
    parameters['oauth_signature'] = 'wrongsignature'
    parameters['oauth_nonce'] = 'anotheraccessresourcenonce'
    response = app.post("/protected", parameters,status=401)

    assert '401 Invalid signature. Expected signature base string: POST' in response.status 
    assert 'Invalid signature. Expected signature base string: POST' in response.body

    response = app.post("/protected",status=401)

    #TODO - why are we getting "Invalid OAuth parameters instead of Invalid request parameters"
    assert response.status == '401 Invalid OAuth parameters'
    assert response.headers['WWW-Authenticate'] == 'OAuth realm="http://events.example.net/"'
    assert response.body == 'Invalid OAuth parameters'
    
    """
    Revoking Access
    ---------------
    
    If Jane deletes the Access Token of printer.example.com, the Consumer will not 
    be able to access the Protected Resource anymore::
    """
    access_token_key = access_token.key_
    access_token.delete()
    parameters['oauth_nonce'] = 'yetanotheraccessresourcenonce'
    
    oauth_request = OAuthRequest('POST','http://localhost/protected',parameters)
    signature_method = OAuthSignatureMethod_HMAC_SHA1()
    signature = signature_method.build_signature(oauth_request, consumer, 
                                                         access_token)
    
    parameters['oauth_signature'] = signature

    
    response = app.post("/protected", parameters,status=401)

    assert response.status == '401 Invalid access token: %s'%(access_token_key)
    assert response.body == 'Invalid access token: %s'%(access_token_key)

    """
    class OAuthTests(TestCase):
        """
        OAuth authentication:
        * the user would like to access his API data from a third-party website
        * the third-party website proposes a link to get that API data
        * the user is redirected to the API and must log in if not authenticated
        * the API displays a webpage to confirm that the user trusts the third-party website
        * if confirmed, the user is redirected to the third-party website through the callback view
        * the third-party website is able to retrieve data from the API
        """
        urls = 'djangorestframework.tests.oauthentication'

        def setUp(self):
            self.client = Client()
            self.username = '******'
            self.email = '*****@*****.**'
            self.password = '******'
            self.user = User.objects.create_user(self.username, self.email, self.password)

            # OAuth requirements
            self.resource = Resource(name='data', url='/')
            self.resource.save()
            self.CONSUMER_KEY = 'dpf43f3p2l4k3l03'
            self.CONSUMER_SECRET = 'kd94hf93k423kf44'
            self.consumer = Consumer(key=self.CONSUMER_KEY, secret=self.CONSUMER_SECRET,
                                name='api.example.com', user=self.user)
            self.consumer.save()

        def test_oauth_invalid_and_anonymous_access(self):
            """
            Verify that the resource is protected and the OAuth authorization view
            require the user to be logged in.
            """
            response = self.client.get('/')
            self.assertEqual(response.content, 'Invalid request parameters.')
            self.assertEqual(response.status_code, 401)
            response = self.client.get('/oauth/authorize/', follow=True)
            self.assertRedirects(response, '/accounts/login/?next=/oauth/authorize/')

        def test_oauth_authorize_access(self):
            """
            Verify that once logged in, the user can access the authorization page
            but can't display the page because the request token is not specified.
            """
            self.client.login(username=self.username, password=self.password)
            response = self.client.get('/oauth/authorize/', follow=True)
            self.assertEqual(response.content, 'No request token specified.')

        def _create_request_token_parameters(self):
            """
            A shortcut to create request's token parameters.
            """
            return {
                'oauth_consumer_key': self.CONSUMER_KEY,
                'oauth_signature_method': 'PLAINTEXT',
                'oauth_signature': '%s&' % self.CONSUMER_SECRET,
                'oauth_timestamp': str(int(time.time())),
                'oauth_nonce': 'requestnonce',
                'oauth_version': '1.0',
                'oauth_callback': 'http://api.example.com/request_token_ready',
                'scope': 'data',
            }

        def test_oauth_request_token_retrieval(self):
            """
            Verify that the request token can be retrieved by the server.
            """
            response = self.client.get("/oauth/request_token/",
                                        self._create_request_token_parameters())
            self.assertEqual(response.status_code, 200)
            token = list(Token.objects.all())[-1]
            self.failIf(token.key not in response.content)
            self.failIf(token.secret not in response.content)

        def test_oauth_user_request_authorization(self):
            """
            Verify that the user can access the authorization page once logged in
            and the request token has been retrieved.
            """
            # Setup
            response = self.client.get("/oauth/request_token/",
                                        self._create_request_token_parameters())
            token = list(Token.objects.all())[-1]

            # Starting the test here
            self.client.login(username=self.username, password=self.password)
            parameters = {'oauth_token': token.key,}
            response = self.client.get("/oauth/authorize/", parameters)
            self.assertEqual(response.status_code, 200)
            self.failIf(not response.content.startswith('Fake authorize view for api.example.com with params: oauth_token='))
            self.assertEqual(token.is_approved, 0)
            parameters['authorize_access'] = 1 # fake authorization by the user
            response = self.client.post("/oauth/authorize/", parameters)
            self.assertEqual(response.status_code, 302)
            self.failIf(not response['Location'].startswith('http://api.example.com/request_token_ready?oauth_verifier='))
            token = Token.objects.get(key=token.key)
            self.failIf(token.key not in response['Location'])
            self.assertEqual(token.is_approved, 1)

        def _create_access_token_parameters(self, token):
            """
            A shortcut to create access' token parameters.
            """
            return {
                'oauth_consumer_key': self.CONSUMER_KEY,
                'oauth_token': token.key,
                'oauth_signature_method': 'PLAINTEXT',
                'oauth_signature': '%s&%s' % (self.CONSUMER_SECRET, token.secret),
                'oauth_timestamp': str(int(time.time())),
                'oauth_nonce': 'accessnonce',
                'oauth_version': '1.0',
                'oauth_verifier': token.verifier,
                'scope': 'data',
            }

        def test_oauth_access_token_retrieval(self):
            """
            Verify that the request token can be retrieved by the server.
            """
            # Setup
            response = self.client.get("/oauth/request_token/",
                                        self._create_request_token_parameters())
            token = list(Token.objects.all())[-1]
            self.client.login(username=self.username, password=self.password)
            parameters = {'oauth_token': token.key,}
            response = self.client.get("/oauth/authorize/", parameters)
            parameters['authorize_access'] = 1 # fake authorization by the user
            response = self.client.post("/oauth/authorize/", parameters)
            token = Token.objects.get(key=token.key)

            # Starting the test here
            response = self.client.get("/oauth/access_token/", self._create_access_token_parameters(token))
            self.assertEqual(response.status_code, 200)
            self.failIf(not response.content.startswith('oauth_token_secret='))
            access_token = list(Token.objects.filter(token_type=Token.ACCESS))[-1]
            self.failIf(access_token.key not in response.content)
            self.failIf(access_token.secret not in response.content)
            self.assertEqual(access_token.user.username, 'john')

        def _create_access_parameters(self, access_token):
            """
            A shortcut to create access' parameters.
            """
            parameters = {
                'oauth_consumer_key': self.CONSUMER_KEY,
                'oauth_token': access_token.key,
                'oauth_signature_method': 'HMAC-SHA1',
                'oauth_timestamp': str(int(time.time())),
                'oauth_nonce': 'accessresourcenonce',
                'oauth_version': '1.0',
            }
            oauth_request = oauth.Request.from_token_and_callback(access_token,
                http_url='http://testserver/', parameters=parameters)
            signature_method = oauth.SignatureMethod_HMAC_SHA1()
            signature = signature_method.sign(oauth_request, self.consumer, access_token)
            parameters['oauth_signature'] = signature
            return parameters

        def test_oauth_protected_resource_access(self):
            """
            Verify that the request token can be retrieved by the server.
            """
            # Setup
            response = self.client.get("/oauth/request_token/",
                                        self._create_request_token_parameters())
            token = list(Token.objects.all())[-1]
            self.client.login(username=self.username, password=self.password)
            parameters = {'oauth_token': token.key,}
            response = self.client.get("/oauth/authorize/", parameters)
            parameters['authorize_access'] = 1 # fake authorization by the user
            response = self.client.post("/oauth/authorize/", parameters)
            token = Token.objects.get(key=token.key)
            response = self.client.get("/oauth/access_token/", self._create_access_token_parameters(token))
            access_token = list(Token.objects.filter(token_type=Token.ACCESS))[-1]

            # Starting the test here
            response = self.client.get("/", self._create_access_token_parameters(access_token))
            self.assertEqual(response.status_code, 200)
            self.assertEqual(response.content, '{"resource": "Protected!"}')
Esempio n. 19
0
class Test1(TestCase):
    def setUp(self):
        jane = User.objects.create_user('jane', '*****@*****.**', 'toto')

        self.resource = Resource(name='photos', url='/oauth/photo/')
        self.resource.save()
        self.CONSUMER_KEY = 'dpf43f3p2l4k3l03'
        self.CONSUMER_SECRET = 'kd94hf93k423kf44'
        self.consumer = Consumer(key=self.CONSUMER_KEY,
                                 secret=self.CONSUMER_SECRET,
                                 name='printer.example.com',
                                 user=jane)
        self.consumer.save()

    def test_1(self):
        """Obtaining a Request Token"""

        response = self.client.get("/oauth/request_token/")
        self.assertEqual(response.status_code, httplib.UNAUTHORIZED)

        # depends on REALM_KEY_NAME Django setting
        self.assertEqual(response._headers['www-authenticate'],
                         ('WWW-Authenticate', 'OAuth realm=""'))
        self.assertEqual(response.content, 'Invalid request parameters.')

        # The Consumer sends the following HTTP POST request to the Service Provider

        parameters = {
            'oauth_consumer_key': self.CONSUMER_KEY,
            'oauth_signature_method': 'PLAINTEXT',
            'oauth_signature': '%s&' % self.CONSUMER_SECRET,
            'oauth_timestamp': str(int(time.time())),
            'oauth_nonce': 'requestnonce',
            'oauth_version': '1.0',
            'oauth_callback': 'http://printer.example.com/request_token_ready',
            'scope': 'photos',  # custom argument to specify Protected Resource
        }
        response = self.client.get("/oauth/request_token/", parameters)

        # The Service Provider checks the signature and replies with an unauthorized
        # Request Token in the body of the HTTP response::

        self.assertEqual(response.status_code, httplib.OK)

        self.assertTrue("oauth_token_secret=" in response.content)
        self.assertTrue("oauth_token=" in response.content)
        self.assertTrue("oauth_callback_confirmed=true" in response.content)

        token = list(Token.objects.all())[-1]
        self.assertTrue(token.key in response.content)
        self.assertTrue(token.secret in response.content)
        self.assertEqual(token.callback,
                         u'http://printer.example.com/request_token_ready')
        self.assertTrue(token.callback_confirmed)

        # If you try to access a resource with a wrong scope, it will return an error::
        # This is not supported.
        #        parameters['scope'] = 'videos'
        #        parameters['oauth_nonce'] = 'requestnoncevideos'
        #        response = self.client.get("/oauth/request_token/", parameters)
        #        print "-------"
        #        print response
        #        print "-------"
        #        self.assertEqual(response.status_code, httplib.UNAUTHORIZED)
        #        self.assertEqual(response.content, 'Resource videos does not exist.')

        parameters['scope'] = 'photos'  # restore

        # If you try to put a wrong callback, it will return an error::

        parameters['oauth_callback'] = 'wrongcallback'
        parameters['oauth_nonce'] = 'requestnoncewrongcallback'
        response = self.client.get("/oauth/request_token/", parameters)
        self.assertEqual(response.status_code, httplib.UNAUTHORIZED)
        self.assertEqual(response.content, 'Invalid callback URL.')

        # If you do not provide any callback (i.e. oob), the Service Provider SHOULD
        # display the value of the verification code::

        parameters['oauth_callback'] = 'oob'
        parameters['oauth_nonce'] = 'requestnonceoob'
        response = self.client.get("/oauth/request_token/", parameters)
        self.assertEqual(response.status_code, httplib.OK)
        self.assertTrue("oauth_token_secret=" in response.content)
        self.assertTrue("oauth_token=" in response.content)
        self.assertTrue("oauth_callback_confirmed=true" in response.content)

        oobtoken = list(Token.objects.all())[-1]
        self.assertTrue(oobtoken.key in response.content)
        self.assertTrue(oobtoken.secret in response.content)
        self.assertEqual(oobtoken.callback, None)
        self.assertFalse(oobtoken.callback_confirmed)

        # ======== Requesting User Authorization ============

        # The Consumer redirects Jane's browser to the Service Provider User
        # Authorization URL to obtain Jane's approval for accessing her private photos.

        # The Service Provider asks Jane to sign-in using her username and password::
        parameters = {
            'oauth_token': token.key,
        }
        response = self.client.get("/oauth/authorize/", parameters)
        self.assertEqual(response.status_code, httplib.FOUND)

        self.assertTrue(True)
        print response['Location']
        self.assertRedirects(response,
                             '/accounts/login/?next=/oauth/authorize/')
        self.assertTrue(token.key in response['Location'])

        # If successful, asks her if she approves granting printer.example.com access to
        # her private photos. If Jane approves the request, the Service Provider
        # redirects her back to the Consumer's callback URL::

        self.assertTrue(self.client.login(username='******', password='******'))
        self.assertEqual(token.is_approved, 0)

        response = self.client.get("/oauth/authorize/", parameters)
        self.assertEqual(response.status_code, httplib.OK)
        self.assertEqual(
            response.content,
            'Fake authorize view for printer.example.com with params: oauth_token=...'
        )

        # fake authorization by the user
        parameters['authorize_access'] = 1
        response = self.client.post("/oauth/authorize/", parameters)
        self.assertEqual(response.status_code, httplib.FOUND)
        self.assertRedirects(response, "/request_token_ready")

        token = Token.objects.get(key=self.token.key)
        self.assertTrue(token.key in response['Location'])
        self.assertEqual(token.is_approved, 1)

        # without session parameter (previous POST removed it)
        response = self.client.post("/oauth/authorize/", parameters)
        self.assertEqual(response.status_code, httplib.UNAUTHORIZED)
        self.assertEqual(response.content, 'Action not allowed.')

        # fake access not granted by the user (set session parameter again)
        response = self.client.get("/oauth/authorize/", parameters)
        parameters['authorize_access'] = 0
        response = self.client.post("/oauth/authorize/", parameters)
        self.assertEqual(response.status_code, httplib.FOUND)
        self.assertRedirects(response, "/request_token_ready")
        self.client.logout()

        # With OAuth 1.0a, the callback argument can be set to "oob" (out-of-band),
        # you can specify your own default callback view with the
        # ``OAUTH_PROVIDER_CALLBACK_VIEW`` setting::

        #        from oauth_provider.consts import OUT_OF_BAND
        token.callback = OUT_OF_BAND
        token.save()
        parameters = {
            'oauth_token': token.key,
        }
        self.assertTrue(self.client.login(username='******', password='******'))

        response = self.client.get("/oauth/authorize/", parameters)
        parameters['authorize_access'] = 0
        response = self.client.post("/oauth/authorize/", parameters)
        self.assertEqual(response.status_code, httplib.OK)
        self.assertEqual(response.content, 'Fake callback view.')
        self.client.logout()

        # ========== Obtaining an Access Token ===========

        # Now that the Consumer knows Jane approved the Request Token, it asks the
        # Service Provider to exchange it for an Access Token::

        parameters = {
            'oauth_consumer_key': self.CONSUMER_KEY,
            'oauth_token': token.key,
            'oauth_signature_method': 'PLAINTEXT',
            'oauth_signature': '%s&%s' % (self.CONSUMER_SECRET, token.secret),
            'oauth_timestamp': str(int(time.time())),
            'oauth_nonce': 'accessnonce',
            'oauth_version': '1.0',
            'oauth_verifier': self.token.verifier,
            'scope': 'photos',
        }
        response = self.client.get("/oauth/access_token/", parameters)

        # You can use HTTP Authorization header, if you provide both, header will be
        # checked before parameters. It depends on your needs.

        # The Service Provider checks the signature and replies with an Access Token in
        # the body of the HTTP response::
        self.assertEqual(response.status_code, httplib.OK)
        self.assertTrue('oauth_token_secret=' in response.content)
        self.assertTrue('oauth_token=' in response.content)

        access_token = list(Token.objects.filter(token_type=Token.ACCESS))[-1]
        self.assertTrue(access_token.key in response.content)
        self.assertTrue(access_token.secret in response.content)
        self.assertEqual(access_token.user.name, u'jane')

        # The Consumer will not be able to request another Access Token with the same
        # parameters because the Request Token has been deleted once Access Token is
        # created::

        response = self.client.get("/oauth/access_token/", parameters)
        self.assertEqual(response.status_code, httplib.BAD_REQUEST)
        self.assertEqual(response.content, 'Invalid request token.')

        # The Consumer will not be able to request another Access Token with a missing
        # or invalid verifier::

        new_request_token = Token.objects.create_token(
            token_type=Token.REQUEST,
            timestamp=str(int(time.time())),
            consumer=Consumer.objects.get(key=self.CONSUMER_KEY),
            user=User.objects.get(username="******"),
            resource=Resource.objects.get(name='photos'))
        new_request_token.is_approved = True
        new_request_token.save()
        parameters['oauth_token'] = new_request_token.key
        parameters['oauth_signature'] = '%s&%s' % (self.CONSUMER_SECRET,
                                                   new_request_token.secret)
        parameters['oauth_verifier'] = 'invalidverifier'
        response = self.client.get("/oauth/access_token/", parameters)
        self.assertEqual(response.status_code, httplib.BAD_REQUEST)
        self.assertEqual(response.content, 'Invalid OAuth verifier.')

        parameters['oauth_verifier'] = new_request_token.verifier  # restore

        # The Consumer will not be able to request an Access Token if the token is not
        # approved::

        new_request_token.is_approved = False
        new_request_token.save()
        parameters['oauth_nonce'] = 'anotheraccessnonce'
        response = self.client.get("/oauth/access_token/", parameters)
        self.assertEqual(response.status_code, httplib.BAD_REQUEST)
        self.assertEqual(response.content,
                         'Request Token not approved by the user.')

        # Accessing Protected Resources

        # The Consumer is now ready to request the private photo. Since the photo URL is
        # not secure (HTTP), it must use HMAC-SHA1.

        # Generating Signature Base String

        # To generate the signature, it first needs to generate the Signature Base
        # String. The request contains the following parameters (oauth_signature
        # excluded) which are ordered and concatenated into a normalized string::

        parameters = {
            'oauth_consumer_key': self.CONSUMER_KEY,
            'oauth_token': access_token.key,
            'oauth_signature_method': 'HMAC-SHA1',
            'oauth_timestamp': str(int(time.time())),
            'oauth_nonce': 'accessresourcenonce',
            'oauth_version': '1.0',
        }

        # Calculating Signature Value

        # HMAC-SHA1 produces the following digest value as a base64-encoded string
        # (using the Signature Base String as text and kd94hf93k423kf44&pfkkdhi9sl3r4s00
        # as key)::

        import oauth2 as oauth
        oauth_request = oauth.Request.from_token_and_callback(
            access_token,
            http_url='http://testserver/oauth/photo/',
            parameters=parameters)
        signature_method = oauth.SignatureMethod_HMAC_SHA1()
        signature = signature_method.sign(oauth_request, self.consumer,
                                          access_token)

        # Requesting Protected Resource

        # All together, the Consumer request for the photo is::

        parameters['oauth_signature'] = signature
        response = self.client.get("/oauth/photo/", parameters)
        self.assertEqual(response.status_code, httplib.OK)
        self.assertEqual(response.content, 'Protected Resource access!')

        # Otherwise, an explicit error will be raised::

        parameters['oauth_signature'] = 'wrongsignature'
        parameters['oauth_nonce'] = 'anotheraccessresourcenonce'
        response = self.client.get("/oauth/photo/", parameters)
        self.assertEqual(response.status_code, httplib.UNAUTHORIZED)
        self.assertTrue(
            'Invalid signature. Expected signature base string: GET' in
            response.content)

        response = self.client.get("/oauth/photo/")
        self.assertEqual(response.status_code, httplib.UNAUTHORIZED)
        self.assertEqual(response.content, 'Invalid request parameters.')

        # Revoking Access

        # If Jane deletes the Access Token of printer.example.com, the Consumer will not
        # be able to access the Protected Resource anymore::

        access_token.delete()
        # Note that an "Invalid signature" error will be raised here if the
        # token is not revoked by Jane because we reuse a previously used one.
        parameters['oauth_signature'] = signature
        parameters['oauth_nonce'] = 'yetanotheraccessresourcenonce'
        response = self.client.get("/oauth/photo/", parameters)
        self.assertEqual(response.status_code, httplib.UNAUTHORIZED)
        self.assertTrue('Invalid access token: ...', response.content)
Esempio n. 20
0
class Test1(TestCase):
    def setUp(self):
        jane = User.objects.create_user("jane", "*****@*****.**", "toto")

        self.resource = Resource(name="photos", url="/oauth/photo/")
        self.resource.save()
        self.CONSUMER_KEY = "dpf43f3p2l4k3l03"
        self.CONSUMER_SECRET = "kd94hf93k423kf44"
        self.consumer = Consumer(
            key=self.CONSUMER_KEY, secret=self.CONSUMER_SECRET, name="printer.example.com", user=jane
        )
        self.consumer.save()

    def test_1(self):
        """Obtaining a Request Token"""

        response = self.client.get("/oauth/request_token/")
        self.assertEqual(response.status_code, httplib.UNAUTHORIZED)

        # depends on REALM_KEY_NAME Django setting
        self.assertEqual(response._headers["www-authenticate"], ("WWW-Authenticate", 'OAuth realm=""'))
        self.assertEqual(response.content, "Invalid request parameters.")

        # The Consumer sends the following HTTP POST request to the Service Provider

        parameters = {
            "oauth_consumer_key": self.CONSUMER_KEY,
            "oauth_signature_method": "PLAINTEXT",
            "oauth_signature": "%s&" % self.CONSUMER_SECRET,
            "oauth_timestamp": str(int(time.time())),
            "oauth_nonce": "requestnonce",
            "oauth_version": "1.0",
            "oauth_callback": "http://printer.example.com/request_token_ready",
            "scope": "photos",  # custom argument to specify Protected Resource
        }
        response = self.client.get("/oauth/request_token/", parameters)

        # The Service Provider checks the signature and replies with an unauthorized
        # Request Token in the body of the HTTP response::

        self.assertEqual(response.status_code, httplib.OK)

        self.assertTrue("oauth_token_secret=" in response.content)
        self.assertTrue("oauth_token=" in response.content)
        self.assertTrue("oauth_callback_confirmed=true" in response.content)

        token = list(Token.objects.all())[-1]
        self.assertTrue(token.key in response.content)
        self.assertTrue(token.secret in response.content)
        self.assertEqual(token.callback, u"http://printer.example.com/request_token_ready")
        self.assertTrue(token.callback_confirmed)

        # If you try to access a resource with a wrong scope, it will return an error::
        # This is not supported.
        #        parameters['scope'] = 'videos'
        #        parameters['oauth_nonce'] = 'requestnoncevideos'
        #        response = self.client.get("/oauth/request_token/", parameters)
        #        print "-------"
        #        print response
        #        print "-------"
        #        self.assertEqual(response.status_code, httplib.UNAUTHORIZED)
        #        self.assertEqual(response.content, 'Resource videos does not exist.')

        parameters["scope"] = "photos"  # restore

        # If you try to put a wrong callback, it will return an error::

        parameters["oauth_callback"] = "wrongcallback"
        parameters["oauth_nonce"] = "requestnoncewrongcallback"
        response = self.client.get("/oauth/request_token/", parameters)
        self.assertEqual(response.status_code, httplib.UNAUTHORIZED)
        self.assertEqual(response.content, "Invalid callback URL.")

        # If you do not provide any callback (i.e. oob), the Service Provider SHOULD
        # display the value of the verification code::

        parameters["oauth_callback"] = "oob"
        parameters["oauth_nonce"] = "requestnonceoob"
        response = self.client.get("/oauth/request_token/", parameters)
        self.assertEqual(response.status_code, httplib.OK)
        self.assertTrue("oauth_token_secret=" in response.content)
        self.assertTrue("oauth_token=" in response.content)
        self.assertTrue("oauth_callback_confirmed=true" in response.content)

        oobtoken = list(Token.objects.all())[-1]
        self.assertTrue(oobtoken.key in response.content)
        self.assertTrue(oobtoken.secret in response.content)
        self.assertEqual(oobtoken.callback, None)
        self.assertFalse(oobtoken.callback_confirmed)

        # ======== Requesting User Authorization ============

        # The Consumer redirects Jane's browser to the Service Provider User
        # Authorization URL to obtain Jane's approval for accessing her private photos.

        # The Service Provider asks Jane to sign-in using her username and password::
        parameters = {"oauth_token": token.key}
        response = self.client.get("/oauth/authorize/", parameters)
        self.assertEqual(response.status_code, httplib.FOUND)

        self.assertTrue(True)
        print response["Location"]
        self.assertRedirects(response, "/accounts/login/?next=/oauth/authorize/")
        self.assertTrue(token.key in response["Location"])

        # If successful, asks her if she approves granting printer.example.com access to
        # her private photos. If Jane approves the request, the Service Provider
        # redirects her back to the Consumer's callback URL::

        self.assertTrue(self.client.login(username="******", password="******"))
        self.assertEqual(token.is_approved, 0)

        response = self.client.get("/oauth/authorize/", parameters)
        self.assertEqual(response.status_code, httplib.OK)
        self.assertEqual(response.content, "Fake authorize view for printer.example.com with params: oauth_token=...")

        # fake authorization by the user
        parameters["authorize_access"] = 1
        response = self.client.post("/oauth/authorize/", parameters)
        self.assertEqual(response.status_code, httplib.FOUND)
        self.assertRedirects(response, "/request_token_ready")

        token = Token.objects.get(key=self.token.key)
        self.assertTrue(token.key in response["Location"])
        self.assertEqual(token.is_approved, 1)

        # without session parameter (previous POST removed it)
        response = self.client.post("/oauth/authorize/", parameters)
        self.assertEqual(response.status_code, httplib.UNAUTHORIZED)
        self.assertEqual(response.content, "Action not allowed.")

        # fake access not granted by the user (set session parameter again)
        response = self.client.get("/oauth/authorize/", parameters)
        parameters["authorize_access"] = 0
        response = self.client.post("/oauth/authorize/", parameters)
        self.assertEqual(response.status_code, httplib.FOUND)
        self.assertRedirects(response, "/request_token_ready")
        self.client.logout()

        # With OAuth 1.0a, the callback argument can be set to "oob" (out-of-band),
        # you can specify your own default callback view with the
        # ``OAUTH_PROVIDER_CALLBACK_VIEW`` setting::

        #        from oauth_provider.consts import OUT_OF_BAND
        token.callback = OUT_OF_BAND
        token.save()
        parameters = {"oauth_token": token.key}
        self.assertTrue(self.client.login(username="******", password="******"))

        response = self.client.get("/oauth/authorize/", parameters)
        parameters["authorize_access"] = 0
        response = self.client.post("/oauth/authorize/", parameters)
        self.assertEqual(response.status_code, httplib.OK)
        self.assertEqual(response.content, "Fake callback view.")
        self.client.logout()

        # ========== Obtaining an Access Token ===========

        # Now that the Consumer knows Jane approved the Request Token, it asks the
        # Service Provider to exchange it for an Access Token::

        parameters = {
            "oauth_consumer_key": self.CONSUMER_KEY,
            "oauth_token": token.key,
            "oauth_signature_method": "PLAINTEXT",
            "oauth_signature": "%s&%s" % (self.CONSUMER_SECRET, token.secret),
            "oauth_timestamp": str(int(time.time())),
            "oauth_nonce": "accessnonce",
            "oauth_version": "1.0",
            "oauth_verifier": self.token.verifier,
            "scope": "photos",
        }
        response = self.client.get("/oauth/access_token/", parameters)

        # You can use HTTP Authorization header, if you provide both, header will be
        # checked before parameters. It depends on your needs.

        # The Service Provider checks the signature and replies with an Access Token in
        # the body of the HTTP response::
        self.assertEqual(response.status_code, httplib.OK)
        self.assertTrue("oauth_token_secret=" in response.content)
        self.assertTrue("oauth_token=" in response.content)

        access_token = list(Token.objects.filter(token_type=Token.ACCESS))[-1]
        self.assertTrue(access_token.key in response.content)
        self.assertTrue(access_token.secret in response.content)
        self.assertEqual(access_token.user.name, u"jane")

        # The Consumer will not be able to request another Access Token with the same
        # parameters because the Request Token has been deleted once Access Token is
        # created::

        response = self.client.get("/oauth/access_token/", parameters)
        self.assertEqual(response.status_code, httplib.BAD_REQUEST)
        self.assertEqual(response.content, "Invalid request token.")

        # The Consumer will not be able to request another Access Token with a missing
        # or invalid verifier::

        new_request_token = Token.objects.create_token(
            token_type=Token.REQUEST,
            timestamp=str(int(time.time())),
            consumer=Consumer.objects.get(key=self.CONSUMER_KEY),
            user=User.objects.get(username="******"),
            resource=Resource.objects.get(name="photos"),
        )
        new_request_token.is_approved = True
        new_request_token.save()
        parameters["oauth_token"] = new_request_token.key
        parameters["oauth_signature"] = "%s&%s" % (self.CONSUMER_SECRET, new_request_token.secret)
        parameters["oauth_verifier"] = "invalidverifier"
        response = self.client.get("/oauth/access_token/", parameters)
        self.assertEqual(response.status_code, httplib.BAD_REQUEST)
        self.assertEqual(response.content, "Invalid OAuth verifier.")

        parameters["oauth_verifier"] = new_request_token.verifier  # restore

        # The Consumer will not be able to request an Access Token if the token is not
        # approved::

        new_request_token.is_approved = False
        new_request_token.save()
        parameters["oauth_nonce"] = "anotheraccessnonce"
        response = self.client.get("/oauth/access_token/", parameters)
        self.assertEqual(response.status_code, httplib.BAD_REQUEST)
        self.assertEqual(response.content, "Request Token not approved by the user.")

        # Accessing Protected Resources

        # The Consumer is now ready to request the private photo. Since the photo URL is
        # not secure (HTTP), it must use HMAC-SHA1.

        # Generating Signature Base String

        # To generate the signature, it first needs to generate the Signature Base
        # String. The request contains the following parameters (oauth_signature
        # excluded) which are ordered and concatenated into a normalized string::

        parameters = {
            "oauth_consumer_key": self.CONSUMER_KEY,
            "oauth_token": access_token.key,
            "oauth_signature_method": "HMAC-SHA1",
            "oauth_timestamp": str(int(time.time())),
            "oauth_nonce": "accessresourcenonce",
            "oauth_version": "1.0",
        }

        # Calculating Signature Value

        # HMAC-SHA1 produces the following digest value as a base64-encoded string
        # (using the Signature Base String as text and kd94hf93k423kf44&pfkkdhi9sl3r4s00
        # as key)::

        import oauth2 as oauth

        oauth_request = oauth.Request.from_token_and_callback(
            access_token, http_url="http://testserver/oauth/photo/", parameters=parameters
        )
        signature_method = oauth.SignatureMethod_HMAC_SHA1()
        signature = signature_method.sign(oauth_request, self.consumer, access_token)

        # Requesting Protected Resource

        # All together, the Consumer request for the photo is::

        parameters["oauth_signature"] = signature
        response = self.client.get("/oauth/photo/", parameters)
        self.assertEqual(response.status_code, httplib.OK)
        self.assertEqual(response.content, "Protected Resource access!")

        # Otherwise, an explicit error will be raised::

        parameters["oauth_signature"] = "wrongsignature"
        parameters["oauth_nonce"] = "anotheraccessresourcenonce"
        response = self.client.get("/oauth/photo/", parameters)
        self.assertEqual(response.status_code, httplib.UNAUTHORIZED)
        self.assertTrue("Invalid signature. Expected signature base string: GET" in response.content)

        response = self.client.get("/oauth/photo/")
        self.assertEqual(response.status_code, httplib.UNAUTHORIZED)
        self.assertEqual(response.content, "Invalid request parameters.")

        # Revoking Access

        # If Jane deletes the Access Token of printer.example.com, the Consumer will not
        # be able to access the Protected Resource anymore::

        access_token.delete()
        # Note that an "Invalid signature" error will be raised here if the
        # token is not revoked by Jane because we reuse a previously used one.
        parameters["oauth_signature"] = signature
        parameters["oauth_nonce"] = "yetanotheraccessresourcenonce"
        response = self.client.get("/oauth/photo/", parameters)
        self.assertEqual(response.status_code, httplib.UNAUTHORIZED)
        self.assertTrue("Invalid access token: ...", response.content)
Esempio n. 21
0
    def test_oauth_workflow(self):
        request_token_url = 'http://testserver' + reverse(
            'api:oauth_request_token')
        authorize_token_url = 'http://testserver' + reverse(
            'api:oauth_user_authorization')

        # create consumer for tests
        c = Client()
        c.login_user('ggbaker')
        c.logout()
        consumer = Consumer(name='Test Consumer',
                            description='Consumer to do some tests with',
                            status=ACCEPTED,
                            user=User.objects.get(username='******'),
                            xauth_allowed=False)
        consumer.generate_random_codes()
        consumer.save()
        ci = ConsumerInfo(consumer=consumer)
        ci.admin_contact = '*****@*****.**'
        ci.permissions = ['courses', 'grades']
        ci.save()

        # generate request token
        oauth_request = oauth.Request.from_consumer_and_token(
            consumer,
            http_url=request_token_url,
            parameters={'oauth_callback': 'oob'})
        oauth_request.sign_request(oauth.SignatureMethod_HMAC_SHA1(), consumer,
                                   None)

        resp = c.get(request_token_url, **oauth_request.to_header())
        self.assertEqual(resp.status_code, 200)
        request_token = dict(
            urllib.parse.parse_qsl(resp.content.decode('utf8')))

        # get auth verifier
        c.login_user('ggbaker')
        resp = c.get(authorize_token_url,
                     {'oauth_token': request_token['oauth_token']})
        self.assertEqual(resp.status_code, 200)
        resp = c.post(authorize_token_url, {
            'oauth_token': request_token['oauth_token'],
            'authorize_access': 'on'
        })
        self.assertEqual(resp.status_code, 200)
        parser = etree.HTMLParser()
        root = etree.fromstring(resp.content, parser=parser)
        verifier_elt = root.xpath('//*[@id="verifier"]')[0]
        oauth_verifier = verifier_elt.text.strip()
        c.logout()

        # get access token
        token = oauth.Token(request_token['oauth_token'],
                            request_token['oauth_token_secret'])
        token.set_verifier(oauth_verifier)
        oauth_request = oauth.Request.from_consumer_and_token(
            consumer, token, http_url=authorize_token_url)
        oauth_request.sign_request(oauth.SignatureMethod_HMAC_SHA1(), consumer,
                                   token)

        resp = c.get(authorize_token_url, **oauth_request.to_header())
Esempio n. 22
0
def test_oauth1_0():
    """
    Test to veriy OAuth 1.0 flow
    """
    """
    After Jane informs printer.example.com that she would like to print her 
    vacation photo stored at photos.example.net, the printer website tries to 
    access the photo and receives HTTP 401 Unauthorized indicating it is private. 
    The Service Provider includes the following header with the response::
    """

    #TODO - not able to handle /request_token/ - returns 404
    #TODO - add test for reuse of nonce for the request token stage?
    #TODO - add test for oauth params in Authorization, GET and POST
    response = app.get('/request_token', status=401)
    assert response.status == '401 Invalid request parameters.'
    assert response.headers[
        'WWW-Authenticate'] == 'OAuth realm="http://events.example.net/"'
    assert response.body == 'Invalid request parameters.'
    """
    The Consumer sends the following HTTP POST request to the Service Provider::
    """
    import time
    parameters = {
        'oauth_consumer_key': CONSUMER_KEY,
        'oauth_signature_method': 'PLAINTEXT',
        'oauth_signature': '%s&' % CONSUMER_SECRET,
        'oauth_timestamp': str(int(time.time())),
        'oauth_nonce': 'requestnonce',
        'oauth_version': '1.0',
        #'scope': 'default', # custom argument to specify Protected Resource
    }

    response = app.post('/request_token', parameters)
    """
    The Service Provider checks the signature and replies with an unauthorized 
    Request Token in the body of the HTTP response::
    """
    assert response.status == '200 OK'

    tokens = Token.all().fetch(1000)
    #double checking the sanity of the test - there should only be one token in
    #the store at this stage

    assert len(tokens) == 1
    token = tokens[0]
    assert 'oauth_token_secret=%s&oauth_token=%s' % (
        token.secret, token.key_) == response.body

    #Ensure that the token returned is unauthorized request token
    assert token.is_approved == False
    assert token.token_type == Token.REQUEST
    """
    If you try to access a resource with a wrong scope, it will return an error::
    """

    #the scope related tests are not here as they the scope
    #function has not been implemented yet
    #>> parameters['scope'] = 'videos'
    #>>> response = c.get("/oauth/request_token/", parameters)
    #>>> response.status_code
    #401
    #>>> response.content
    #'Resource videos does not exist.'
    """
    Requesting User Authorization
    -----------------------------
    
    The Consumer redirects Jane's browser to the Service Provider User 
    Authorization URL to obtain Jane's approval for accessing her private photos.
    
    The Service Provider asks Jane to sign-in using her username and password::
    
    """
    parameters = {
        'oauth_token': token.key_,
        'oauth_callback': 'http://test.com/request_token_ready',
        'authorize_access': 1,
    }

    response = app.post('/authorize', parameters)
    assert response.status == '302 Moved Temporarily'
    assert response.location ==\
'http://localhost/_ah/login?continue=http%%3A//localhost/authorize%%3Foauth_token%%3D%s%%26oauth_callback%%3Dhttp%%3A//test.com/request_token_ready'%(token.key_)

    #the token details should not be altered by this call
    tokens = Token.all().fetch(1000)
    assert len(tokens) == 1
    token = tokens[0]

    assert token.is_approved == False
    assert token.token_type == Token.REQUEST

    #In reality the user would of been redirected to the Google login page and
    #then redirected to a page where they will be given an opportunity to
    #authorize the application or otherwise.

    #Here we simulate the user being logged (by setting the
    #os.environ['USER_EMAIL']) variable and the user giving authorizing by
    #setting the 'authorize_access' parameter
    #and redirect manually to the authorization page
    os.environ['USER_EMAIL'] = '*****@*****.**'
    response = app.post('/authorize', parameters)

    #verify that the request token is now approved
    tokens = Token.all().fetch(1000)
    assert len(tokens) == 1
    token = tokens[0]

    assert token.is_approved == True
    assert token.token_type == Token.REQUEST

    #verify the response - now that we are approved we should get
    assert response.status == '302 Moved Temporarily'
    assert response.location == 'http://test.com/request_token_ready?oauth_token=%s' % (
        token.key_)

    #TODO add test for case where the user rejects the approval,
    #now the flow assumes that it will always be approved upon logging in
    """
    Obtaining an Access Token
    -------------------------
    
    Now that the Consumer knows Jane approved the Request Token, it asks the 
    Service Provider to exchange it for an Access Token::
    """

    parameters = {
        'oauth_consumer_key': CONSUMER_KEY,
        'oauth_token': token.key_,
        'oauth_signature_method': 'PLAINTEXT',
        'oauth_signature': '%s&%s' % (CONSUMER_SECRET, token.secret),
        'oauth_timestamp': str(int(time.time())),
        'oauth_nonce': 'accessnonce',
        'oauth_version': '1.0',
    }
    response = app.post("/access_token", parameters)
    """
    The Service Provider checks the signature and replies with an Access Token in 
    the body of the HTTP response::
    """

    response.status == '200 OK'
    #verify the access token now

    access_tokens = Token.all()\
        .filter('token_type =',Token.ACCESS).fetch(1000)
    #double checking the sanity of the test - there should only be one token in
    #the store at this stage

    assert len(access_tokens) == 1
    access_token = access_tokens[0]
    assert 'oauth_token_secret=%s&oauth_token=%s' % (
        access_token.secret, access_token.key_) == response.body

    assert str(access_token.user) == '*****@*****.**'
    """
    The Consumer will not be able to request another Access Token with the same
    Nonce::
    """

    nonces = Nonce.all().fetch(1000)
    assert nonces[0].key_ == "accessnonce"

    response = app.post("/access_token", parameters, status=401)

    assert response.status == '401 Nonce already used: accessnonce'
    assert response.body == 'Nonce already used: accessnonce'
    """
    The Consumer will not be able to request an Access Token if the token is not
    approved::
    """

    token.is_approved = False
    token.put()

    parameters['oauth_nonce'] = 'anotheraccessnonce'
    response = app.post("/access_token", parameters, status=401)
    response.status == "401 Consumer key or token key does not match. Make sure your request token is approved. Check your verifier too if you use OAuth 1.0a."
    response.body == 'Consumer key or token key does not match. Make sure your request token is approved. Check your verifier too if you use OAuth 1.0a.'
    """
    Accessing Protected Resources
    -----------------------------
    
    The Consumer is now ready to request the private photo. Since the photo URL is 
    not secure (HTTP), it must use HMAC-SHA1.
    
    Generating Signature Base String
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    To generate the signature, it first needs to generate the Signature Base 
    String. The request contains the following parameters (oauth_signature 
    excluded) which are ordered and concatenated into a normalized string::
    """

    parameters = {
        'oauth_consumer_key': CONSUMER_KEY,
        'oauth_token': access_token.key_,
        'oauth_signature_method': 'HMAC-SHA1',
        'oauth_timestamp': str(int(time.time())),
        'oauth_nonce': 'accessresourcenonce',
        'oauth_version': '1.0',
    }
    """
    Calculating Signature Value
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    HMAC-SHA1 produces the following digest value as a base64-encoded string 
    (using the Signature Base String as text and kd94hf93k423kf44&pfkkdhi9sl3r4s00 
    as key)::
    """

    consumer = Consumer.all().fetch(1000)[0]

    #we dont use the OAuthRequest.from_token_and_callback function as how the
    #original method does as it does a token.key instead of token.key_

    oauth_request = OAuthRequest('POST', 'http://localhost/protected',
                                 parameters)
    signature_method = OAuthSignatureMethod_HMAC_SHA1()
    signature = signature_method.build_signature(oauth_request, consumer,
                                                 access_token)
    """
    Requesting Protected Resource
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    All together, the Consumer request for the photo is::
    """

    parameters['oauth_signature'] = signature
    response = app.post("/protected", parameters)

    assert response.status == '200 OK'
    assert response.body == 'Protected Resource access!'
    """
    Otherwise, an explicit error will be raised::
    """

    parameters['oauth_signature'] = 'wrongsignature'
    parameters['oauth_nonce'] = 'anotheraccessresourcenonce'
    response = app.post("/protected", parameters, status=401)

    assert '401 Invalid signature. Expected signature base string: POST' in response.status
    assert 'Invalid signature. Expected signature base string: POST' in response.body

    response = app.post("/protected", status=401)

    #TODO - why are we getting "Invalid OAuth parameters instead of Invalid request parameters"
    assert response.status == '401 Invalid OAuth parameters'
    assert response.headers[
        'WWW-Authenticate'] == 'OAuth realm="http://events.example.net/"'
    assert response.body == 'Invalid OAuth parameters'
    """
    Revoking Access
    ---------------
    
    If Jane deletes the Access Token of printer.example.com, the Consumer will not 
    be able to access the Protected Resource anymore::
    """
    access_token_key = access_token.key_
    access_token.delete()
    parameters['oauth_nonce'] = 'yetanotheraccessresourcenonce'

    oauth_request = OAuthRequest('POST', 'http://localhost/protected',
                                 parameters)
    signature_method = OAuthSignatureMethod_HMAC_SHA1()
    signature = signature_method.build_signature(oauth_request, consumer,
                                                 access_token)

    parameters['oauth_signature'] = signature

    response = app.post("/protected", parameters, status=401)

    assert response.status == '401 Invalid access token: %s' % (
        access_token_key)
    assert response.body == 'Invalid access token: %s' % (access_token_key)
    """
    class OAuthTests(TestCase):
        """
        OAuth authentication:
        * the user would like to access his API data from a third-party website
        * the third-party website proposes a link to get that API data
        * the user is redirected to the API and must log in if not authenticated
        * the API displays a webpage to confirm that the user trusts the third-party website
        * if confirmed, the user is redirected to the third-party website through the callback view
        * the third-party website is able to retrieve data from the API
        """
        urls = 'djangorestframework.tests.oauthentication'

        def setUp(self):
            self.client = Client()
            self.username = '******'
            self.email = '*****@*****.**'
            self.password = '******'
            self.user = User.objects.create_user(self.username, self.email, self.password)

            # OAuth requirements
            self.resource = Resource(name='data', url='/')
            self.resource.save()
            self.CONSUMER_KEY = 'dpf43f3p2l4k3l03'
            self.CONSUMER_SECRET = 'kd94hf93k423kf44'
            self.consumer = Consumer(key=self.CONSUMER_KEY, secret=self.CONSUMER_SECRET,
                                name='api.example.com', user=self.user)
            self.consumer.save()

        def test_oauth_invalid_and_anonymous_access(self):
            """
            Verify that the resource is protected and the OAuth authorization view
            require the user to be logged in.
            """
            response = self.client.get('/')
            self.assertEqual(response.content, 'Invalid request parameters.')
            self.assertEqual(response.status_code, 401)
            response = self.client.get('/oauth/authorize/', follow=True)
            self.assertRedirects(response, '/accounts/login/?next=/oauth/authorize/')

        def test_oauth_authorize_access(self):
            """
            Verify that once logged in, the user can access the authorization page
            but can't display the page because the request token is not specified.
            """
            self.client.login(username=self.username, password=self.password)
            response = self.client.get('/oauth/authorize/', follow=True)
            self.assertEqual(response.content, 'No request token specified.')

        def _create_request_token_parameters(self):
            """
            A shortcut to create request's token parameters.
            """
            return {
                'oauth_consumer_key': self.CONSUMER_KEY,
                'oauth_signature_method': 'PLAINTEXT',
                'oauth_signature': '%s&' % self.CONSUMER_SECRET,
                'oauth_timestamp': str(int(time.time())),
                'oauth_nonce': 'requestnonce',
                'oauth_version': '1.0',
                'oauth_callback': 'http://api.example.com/request_token_ready',
                'scope': 'data',
            }

        def test_oauth_request_token_retrieval(self):
            """
            Verify that the request token can be retrieved by the server.
            """
            response = self.client.get("/oauth/request_token/",
                                        self._create_request_token_parameters())
            self.assertEqual(response.status_code, 200)
            token = list(Token.objects.all())[-1]
            self.failIf(token.key not in response.content)
            self.failIf(token.secret not in response.content)

        def test_oauth_user_request_authorization(self):
            """
            Verify that the user can access the authorization page once logged in
            and the request token has been retrieved.
            """
            # Setup
            response = self.client.get("/oauth/request_token/",
                                        self._create_request_token_parameters())
            token = list(Token.objects.all())[-1]

            # Starting the test here
            self.client.login(username=self.username, password=self.password)
            parameters = {'oauth_token': token.key,}
            response = self.client.get("/oauth/authorize/", parameters)
            self.assertEqual(response.status_code, 200)
            self.failIf(not response.content.startswith('Fake authorize view for api.example.com with params: oauth_token='))
            self.assertEqual(token.is_approved, 0)
            parameters['authorize_access'] = 1 # fake authorization by the user
            response = self.client.post("/oauth/authorize/", parameters)
            self.assertEqual(response.status_code, 302)
            self.failIf(not response['Location'].startswith('http://api.example.com/request_token_ready?oauth_verifier='))
            token = Token.objects.get(key=token.key)
            self.failIf(token.key not in response['Location'])
            self.assertEqual(token.is_approved, 1)

        def _create_access_token_parameters(self, token):
            """
            A shortcut to create access' token parameters.
            """
            return {
                'oauth_consumer_key': self.CONSUMER_KEY,
                'oauth_token': token.key,
                'oauth_signature_method': 'PLAINTEXT',
                'oauth_signature': '%s&%s' % (self.CONSUMER_SECRET, token.secret),
                'oauth_timestamp': str(int(time.time())),
                'oauth_nonce': 'accessnonce',
                'oauth_version': '1.0',
                'oauth_verifier': token.verifier,
                'scope': 'data',
            }

        def test_oauth_access_token_retrieval(self):
            """
            Verify that the request token can be retrieved by the server.
            """
            # Setup
            response = self.client.get("/oauth/request_token/",
                                        self._create_request_token_parameters())
            token = list(Token.objects.all())[-1]
            self.client.login(username=self.username, password=self.password)
            parameters = {'oauth_token': token.key,}
            response = self.client.get("/oauth/authorize/", parameters)
            parameters['authorize_access'] = 1 # fake authorization by the user
            response = self.client.post("/oauth/authorize/", parameters)
            token = Token.objects.get(key=token.key)

            # Starting the test here
            response = self.client.get("/oauth/access_token/", self._create_access_token_parameters(token))
            self.assertEqual(response.status_code, 200)
            self.failIf(not response.content.startswith('oauth_token_secret='))
            access_token = list(Token.objects.filter(token_type=Token.ACCESS))[-1]
            self.failIf(access_token.key not in response.content)
            self.failIf(access_token.secret not in response.content)
            self.assertEqual(access_token.user.username, 'john')

        def _create_access_parameters(self, access_token):
            """
            A shortcut to create access' parameters.
            """
            parameters = {
                'oauth_consumer_key': self.CONSUMER_KEY,
                'oauth_token': access_token.key,
                'oauth_signature_method': 'HMAC-SHA1',
                'oauth_timestamp': str(int(time.time())),
                'oauth_nonce': 'accessresourcenonce',
                'oauth_version': '1.0',
            }
            oauth_request = oauth.Request.from_token_and_callback(access_token,
                http_url='http://testserver/', parameters=parameters)
            signature_method = oauth.SignatureMethod_HMAC_SHA1()
            signature = signature_method.sign(oauth_request, self.consumer, access_token)
            parameters['oauth_signature'] = signature
            return parameters

        def test_oauth_protected_resource_access(self):
            """
            Verify that the request token can be retrieved by the server.
            """
            # Setup
            response = self.client.get("/oauth/request_token/",
                                        self._create_request_token_parameters())
            token = list(Token.objects.all())[-1]
            self.client.login(username=self.username, password=self.password)
            parameters = {'oauth_token': token.key,}
            response = self.client.get("/oauth/authorize/", parameters)
            parameters['authorize_access'] = 1 # fake authorization by the user
            response = self.client.post("/oauth/authorize/", parameters)
            token = Token.objects.get(key=token.key)
            response = self.client.get("/oauth/access_token/", self._create_access_token_parameters(token))
            access_token = list(Token.objects.filter(token_type=Token.ACCESS))[-1]

            # Starting the test here
            response = self.client.get("/", self._create_access_token_parameters(access_token))
            self.assertEqual(response.status_code, 200)
            self.assertEqual(response.content, '{"resource": "Protected!"}')