예제 #1
0
    def oauth_params(self, action, method='POST', uid=None, key=None):
        secret = None
        cohort = None
        oauth_credentials = getattr(settings, 'LTI_OAUTH_CREDENTIALS', {})
        if not key:
            keys = oauth_credentials.keys()
            if len(keys):
                key = keys[0]
            else:
                cohort = Cohort.objects.first()
                if cohort:
                    key = cohort.oauth_key
        if key:
            if key in oauth_credentials:
                secret = oauth_credentials.get(key)
            else:
                if not cohort:
                    cohorts = Cohort.objects.filter(oauth_key=key).all()
                    cohort = None
                    if cohorts:
                        cohort = cohorts[0]
                if cohort:
                    secret = cohort.oauth_secret

        if not secret:
            return None

        consumer = Consumer(key, secret)

        nonce = ''
        for i in range(32):
            nonce = nonce + str(randint(0,9))
        nonce = int(nonce)

        if not uid:
            uid = str(nonce)

        signer = SignatureMethod()
        oauth_params = {
            'oauth_consumer_key': key,
            'oauth_signature_method': signer.name,
            'oauth_timestamp': str(int(time.time())),
            'oauth_nonce': str(nonce),
            'user_id': uid,
            'oauth_version': '1.0',
            'lti_message_type': 'basic-lti-launch-request',
        }
        request = Request(method, action, oauth_params)
        oauth_params['oauth_signature'] = signer.sign(request, consumer, None)
        return oauth_params
예제 #2
0
    def testRequestAvatarId(self):
        """
        L{FacadeOAuthChecker.requestAvatarId} creates a
        L{FluidinfoSession} for the authenticated user only if credentials are
        correct.
        """
        UserAPI().create([(u'consumer', u'secret', u'Consumer',
                           u'*****@*****.**'),
                          (u'user', u'secret', u'User', u'*****@*****.**')])
        consumerUser = getUser(u'consumer')
        user = getUser(u'user')
        api = OAuthConsumerAPI()
        consumer = api.register(consumerUser)
        token = api.getAccessToken(consumerUser, user)
        self.store.commit()

        timestamp = 1314976811
        headers = {'header1': 'foo'}
        arguments = 'argument1=bar'
        # FIXME This isn't ideal.  It'd be better to use a hard-coded
        # signature, because then we'd know when something changed.  It's hard
        # to do that, though, because the encrypted token generated by
        # fluiddb.util.minitoken is always different. -jkakar
        request = Request.from_request('GET', u'https://fluidinfo.com/foo',
                                       headers, {'argument1': 'bar'})
        signature = SignatureMethod_HMAC_SHA1().sign(request, consumer, None)
        nonce = 'nonce'
        credentials = OAuthCredentials('fluidinfo.com', consumerUser.username,
                                       token.encrypt(), 'HMAC-SHA1', signature,
                                       timestamp, nonce, 'GET',
                                       u'https://fluidinfo.com/foo', headers,
                                       arguments)
        session = yield self.checker.requestAvatarId(credentials)
        self.assertEqual(user.username, session.auth.username)
        self.assertEqual(user.objectID, session.auth.objectID)
예제 #3
0
    def testAuthenticateUserWithOAuthWithMixedCaseInToken(self):
        """
        L{FacadeAuthMixin.authenticateUserWithOAuth} ignores the case in the
        username in the token.
        """
        UserAPI().create([
            (u'consumer', u'secret', u'Consumer', u'*****@*****.**'),
            (u'user', u'secret', u'User', u'*****@*****.**')])
        consumerUser = getUser(u'consumer')
        user = getUser(u'user')
        api = OAuthConsumerAPI()
        consumer = api.register(consumerUser)
        token = dataToToken(consumer.secret,
                            {'username': u'UseR',
                             'creationTime': '20121228-161823'})

        self.store.commit()
        timestamp = 1314976811
        headers = {'header1': 'foo'}
        arguments = 'argument1=bar'
        request = Request.from_request('GET', u'https://fluidinfo.com/foo',
                                       headers, {'argument1': 'bar'})
        signature = SignatureMethod_HMAC_SHA1().sign(request,
                                                     consumer, None)
        nonce = 'nonce'
        credentials = OAuthCredentials(
            'fluidinfo.com', consumerUser.username, token,
            'HMAC-SHA1', signature, timestamp, nonce, 'GET',
            u'https://fluidinfo.com/foo', headers, arguments)
        session = yield self.facade.authenticateUserWithOAuth(credentials)
        self.assertEqual(user.username, session.auth.username)
        self.assertEqual(user.objectID, session.auth.objectID)
예제 #4
0
    def testAuthenticateUserWithOAuth(self):
        """
        L{FacadeAuthMixin.authenticateUserWithOAuth} creates a
        L{FluidinfoSession} for the authenticated user only if credentials are
        correct.
        """
        UserAPI().create([
            (u'consumer', u'secret', u'Consumer', u'*****@*****.**'),
            (u'user', u'secret', u'User', u'*****@*****.**')])
        consumerUser = getUser(u'consumer')
        user = getUser(u'user')
        api = OAuthConsumerAPI()
        consumer = api.register(consumerUser)
        token = api.getAccessToken(consumerUser, user)

        self.store.commit()
        timestamp = 1314976811
        headers = {'header1': 'foo'}
        arguments = 'argument1=bar'
        request = Request.from_request('GET', u'https://fluidinfo.com/foo',
                                       headers, {'argument1': 'bar'})
        signature = SignatureMethod_HMAC_SHA1().sign(request,
                                                     consumer, None)
        nonce = 'nonce'
        credentials = OAuthCredentials(
            'fluidinfo.com', consumerUser.username, token.encrypt(),
            'HMAC-SHA1', signature, timestamp, nonce, 'GET',
            u'https://fluidinfo.com/foo', headers, arguments)
        session = yield self.facade.authenticateUserWithOAuth(credentials)
        self.assertEqual(user.username, session.auth.username)
        self.assertEqual(user.objectID, session.auth.objectID)
 def _get_signed_oauth_request(self, path, method, data=None):
     data = data if data is not None else self._data
     url = self._url_base + path
     method = method if method else 'GET'
     req = Request.from_consumer_and_token(self.consumer, {}, method, url,
                                           data)
     req.sign_request(SignatureMethod_HMAC_SHA1(), self.consumer, None)
     return req
예제 #6
0
파일: api.py 프로젝트: mogi/sandbox
 def get_access_token(self, key, secret, verifier):
     token = Token(key, secret)
     token.set_verifier(verifier)
     oauth_request = Request.from_consumer_and_token(
         self.consumer, http_method="POST", token=token,
         http_url=self.request_token_url)
     oauth_request.sign_request(SignatureMethod_HMAC_SHA1(),
                                self.consumer, None)
     return self.fetch_access_token(oauth_request)
예제 #7
0
 def get_oauth_request(self, url=None, token=None, **params):
     request = OAuthRequest.from_consumer_and_token(self.get_consumer(),
                                                    token=token,
                                                    http_url=url
                                                    or self.ENDPOINT,
                                                    parameters=params)
     request.sign_request(SignatureMethod_HMAC_SHA1(), self.get_consumer(),
                          token)
     return request
예제 #8
0
 def oauth_post_request(self, token, url, params):
     """Generate OAuth request, setups callback url"""
     if 'oauth_verifier' in self.data:
         params['oauth_verifier'] = self.data['oauth_verifier']
     request = OAuthRequest.from_consumer_and_token(self.consumer,
                                                    token=token,
                                                    http_url=url,
                                                    parameters=params,
                                                    http_method='POST')
     request.sign_request(SignatureMethod_HMAC_SHA1(), self.consumer, token)
     return request
예제 #9
0
파일: api.py 프로젝트: mogi/sandbox
 def get_auth_url(self, callback_url):
     # get request token
     oauth_request = Request.from_consumer_and_token(
         self.consumer, http_method="POST",
         http_url=self.request_token_url,
         parameters={'oauth_callback': callback_url})
     oauth_request.sign_request(SignatureMethod_HMAC_SHA1(),
                                self.consumer, None)
     token = self.fetch_request_token(oauth_request)
     # get authorization url
     oauth_request = Request.from_token_and_callback(
                         token=token, http_url=self.authorization_url)
     return oauth_request.to_url(), token
예제 #10
0
 def _get_auth_headers(self, method, url):
     oauth_params = {
         'oauth_version': "1.0",
         'oauth_nonce': generate_nonce(),
         'oauth_timestamp': int(time.time())
     }
     oauth_request = OAuthRequest(method, url, parameters=oauth_params)
     consumer = Consumer(self.client, self.oauth_secret)
     oauth_request.sign_request(SignatureMethod_HMAC_SHA1(), consumer, None)
     auth_headers = oauth_request.to_header()
     auth_headers['Authorization'] = auth_headers['Authorization'].encode(
         'utf-8')
     return auth_headers
예제 #11
0
 def __init__(self, customer_key=None, customer_secret=None):
     self.base_url = 'https://www.plurk.com'
     self.request_token_url = '/OAuth/request_token'
     self.authorization_url = '/OAuth/authorize'
     self.access_token_url = '/OAuth/access_token'
     self.customer_key = customer_key
     self.customer_secret = customer_secret
     self.sign_method = SignatureMethod_HMAC_SHA1()
     self.consumer = None
     self.token = None
     self.oauth_token = {}
     if self.customer_key and self.customer_secret:
         self.consumer = Consumer(self.customer_key, self.customer_secret)
예제 #12
0
    def oauth_request(self, token, url, extra_params=None):
        """Generate OAuth request, setups callback url"""
        params = {'oauth_callback': self.redirect_uri}
        if extra_params:
            params.update(extra_params)

        if 'oauth_verifier' in self.data:
            params['oauth_verifier'] = self.data['oauth_verifier']
        request = OAuthRequest.from_consumer_and_token(self.consumer,
                                                       token=token,
                                                       http_url=url,
                                                       parameters=params)
        request.sign_request(SignatureMethod_HMAC_SHA1(), self.consumer, token)
        return request
예제 #13
0
    def verifySignature(self, secret):
        """See L{IOAuthCredentials#verifySignature}."""
        consumer = Consumer(key=self.consumerKey, secret=secret)
        oauthRequest = Request.from_request(self.method,
                                            self.url,
                                            headers=self.headers,
                                            query_string=self.arguments)

        # verify the request has been oauth authorized, we only support
        # HMAC-SHA1, reject OAuth signatures if they use a different method
        if self.signatureMethod != 'HMAC-SHA1':
            raise NotImplementedError('Unknown signature method: %s' %
                                      self.signatureMethod)
        signatureMethod = SignatureMethod_HMAC_SHA1()
        result = signatureMethod.check(oauthRequest, consumer, None,
                                       self.signature)
        return result
예제 #14
0
def build_consumer_oauth_request(backend, token, url, redirect_uri='/',
                                 oauth_verifier=None, extra_params=None):
    """Builds a Consumer OAuth request."""
    params = {'oauth_callback': redirect_uri}
    if extra_params:
        params.update(extra_params)

    if oauth_verifier:
        params['oauth_verifier'] = oauth_verifier

    consumer = OAuthConsumer(*backend.get_key_and_secret())
    request = OAuthRequest.from_consumer_and_token(consumer,
                                                   token=token,
                                                   http_url=url,
                                                   parameters=params)
    request.sign_request(SignatureMethod_HMAC_SHA1(), consumer, token)
    return request
예제 #15
0
def auth(callback_url):
    # setup
    client = SimpleClient(SERVER, REQUEST_TOKEN_URL, ACCESS_TOKEN_URL)
    consumer = Consumer(CONSUMER_KEY, CONSUMER_SECRET)

    # get request token
    oauth_request = Request.from_consumer_and_token(
        consumer,
        http_method="POST",
        http_url=client.request_token_url,
        parameters={'oauth_callback': callback_url})
    oauth_request.sign_request(SignatureMethod_HMAC_SHA1(), consumer, None)
    token = client.fetch_request_token(oauth_request)
    cache.set('app.root.view.post::oauth_token', token.key, 300)
    cache.set('app.root.view.post::oauth_token_secret', token.secret, 300)

    oauth_request = Request.from_token_and_callback(token=token,
                                                    http_url=AUTHORIZATION_URL)
    return oauth_request.to_url()
예제 #16
0
class OAuthTest(OAuthTestCase):
    '''Tests a basic OAuth-based API.'''

    urls = 'project.api.urls'

    signature_method = SignatureMethod_HMAC_SHA1()

    @classmethod
    def setUpClass(cls):
        super(OAuthTest, cls).setUpClass()
        cls.two_legged_api_path = '/two/'
        cls.two_legged_api_url = cls.get_url(cls.two_legged_api_path)
        cls.three_legged_api_path = '/three/'
        cls.three_legged_api_url = cls.get_url(cls.three_legged_api_path)

    def setUp(self):
        self.session = orm.sessionmaker()
        self.cuser = User.create_user('testoauth',
                                      '*****@*****.**', 'testoauth')
        data = dict(name=u'Piston Test OAuth',
                    description=u'A test consumer for OAuth.',
                    session=self.session, user=self.cuser)
        self.consumer = Consumer.create(**data)
        self.old_store = getattr(settings, 'PISTON_OAUTH_STORE', None)
        settings.PISTON_OAUTH_STORE = BAPH_PISTON_OAUTH_STORE

    def tearDown(self):
        self.session.delete(self.cuser)
        self.session.delete(self.consumer)
        self.session.commit()
        del self.cuser
        del self.consumer
        settings.PISTON_OAUTH_STORE = self.old_store
        del self.old_store
        self.session.close()
        orm.sessionmaker_remove()

    def test_unauthorized(self):
        response = self.client.get(self.three_legged_api_path)
        self.assertEqual(response.status_code, 401)
        response = self.client.get(self.two_legged_api_path)
        self.assertEqual(response.status_code, 401)

    def test_get_request_token(self):
        self.get_request_token()

    def authorize_request_token(self, request_token_key):
        return super(OAuthTest,
                     self).authorize_request_token(request_token_key,
                                                   'testoauth', 'testoauth')

    def test_authorize_request_token_without_callback(self):
        request_token = self.get_request_token('oob')
        response = self.authorize_request_token(request_token.key)

        self.assertEquals(response.status_code, 200)

    def test_authorize_request_token_with_callback(self):
        request_token = self.get_request_token(CALLBACK_URL)
        response = self.authorize_request_token(request_token.key)

        self.assertEquals(response.status_code, 302)
        self.assert_(response['Location'].startswith(CALLBACK_URL))

    def test_get_access_token(self):
        self.get_access_token(CALLBACK_URL)

    def test_two_legged_api(self):
        request = Request.from_consumer_and_token(self.consumer, None, 'GET',
                                                  self.two_legged_api_url,
                                                  {'msg': 'expected response'})
        request.sign_request(self.signature_method, self.consumer, None)

        response = self.client.get(self.two_legged_api_path, request)
        self.assertEquals(response.status_code, 200)
        self.assertIn('world', response.content)

    def test_three_legged_api(self):
        consumer = OAConsumer(self.consumer.key, self.consumer.secret)
        access_token = self.get_access_token(CALLBACK_URL)

        request = Request.from_consumer_and_token(consumer, access_token,
                                                  'GET',
                                                  self.three_legged_api_url,
                                                  {'msg': 'expected response'})
        request.sign_request(self.signature_method, consumer,
                             access_token)

        response = self.client.get(self.three_legged_api_path, request)
        self.assertEquals(response.status_code, 200)
        self.assertIn('world', response.content)
예제 #17
0
 def __init__(self, *args, **kwargs):
     super(OAuthBackend, self).__init__(*args, **kwargs)
     self.consumer = Consumer(self.CONSUMER_KEY, self.CONSUMER_SECRET)
     self.signature_method = SignatureMethod_HMAC_SHA1()
예제 #18
0
class Base(object):
    """
        Base class for all Photobucket APIs.
    """

    # Photobucket API main endpoint
    DOMAIN = 'api.photobucket.com'

    # Used per API to define the main URI for that specific API.
    # E.g URI = /album/! - Will send a request to self.DOMAIN + /album/!
    # The ! is a special character used by Photobucket to indicate an identifier.
    # Ex. /album/!?id=identifier
    # All the APIs use an identifier for about 98% of all their methods, that's why
    # its already in the URI to save me the burden of putting it in almost every call :).
    URI = '/'

    # Url for user authentication.
    LOGIN = '******'

    def __init__(self,
                 key,
                 secret,
                 token=None,
                 token_secret=None,
                 subdomain=None):
        """
            Base API Class. All Photobucket APIs need to subclass.

            @key: Your photobucket API Key.
            @secret: Your photobucket API secret.
            @token: Can be a request or access token.
            @token_secret: Can be a request or access secret.
            @subdomain: The subdomain or "silo" to use when required by API. 
                        See http://bit.ly/Nla3WD
        """

        self.key = key
        self.secret = secret
        self.token = token
        self.token_secret = token_secret
        self.subdomain = subdomain or self.DOMAIN

    def get_timestamp(self):
        return self.make_request('time', base_uri=Base.URI)

    # These four methods send pass Base.URI as base_uri to allow access
    # from any Photobucket API ( Album.ping ) since they are essential.

    def ping(self, method="GET"):
        return self.make_request('ping', base_uri=Base.URI, method=method)

    def login_request(self):
        """ 
            Get a login request token to use during web authentication.
        """
        return self.make_request('login/request',
                                 base_uri=Base.URI,
                                 method='POST')

    def get_access_token(self):
        return self.make_request('login/access',
                                 base_uri=Base.URI,
                                 method='POST')

    def get_login_url(self, token=None, extra=None):
        """
            Returns the login url for the provided token.
            This assumes that token or self.token is a Request Token.
        """
        if self.token is None and token is None:
            raise PhotobucketAPIError(
                "token needs to be set on instance or provided.")
        params = {}
        if extra:
            params['extra'] = extra
        params.update(dict(oauth_token=token or self.token))
        return "%s?%s" % (self.LOGIN, urllib.urlencode(params))

    def make_request(self,
                     url,
                     base_uri=None,
                     params=None,
                     auth=REQUIRED,
                     method="GET",
                     silo=False,
                     **kwargs):
        """
            Makes a request to Photobucket API.
            @url: The REST path to be requested after the [identifier]. By default this
                  value is appended to self.URI.
                  E.g. 
                    self.URI = /album/!
                    url = /share/all
                    The uri to request will be /album/!/share/all
            @base_uri: Allows for a quick override of self.URI per call.
            @params: A dictionary of parameters to send with the request.
            @auth: An Integer that determines whether this request needs to be authenticated.
            @method: The HTTP method to be used.
            @silo: Boolean. If True then this request will be sent to a specific silo/subdomain.

        """

        params = params or dict()
        body = kwargs.get('body', '')
        headers = {
            'User-Agent': 'python-photobucket/0.2 (Language=Python)',
            'Content-type': 'application/x-www-form-urlencoded'
        }
        headers.update(kwargs.get('extra_headers', {}))
        # Unless explicitly provided, set the default response format to json.
        params.setdefault('format', 'json')
        if 'id' in params:
            params['id'] = self.clean_identifier(params['id'])
        # Remove all params with a value of "None"
        params = remove_empty(params)

        # Begin auth stuff...
        token = None
        consumer = OAuthConsumer(key=self.key, secret=self.secret)
        if auth in (REQUIRED, OPTIONAL):
            # Setup the oauth token
            try:
                token = Token(key=self.token, secret=self.token_secret)
            except ValueError, e:
                if auth == REQUIRED:
                    # Only raise the exception if auth is required.
                    raise PhotobucketAPIError(
                        "Token and Token secret must be set.")

        # Give priority to base_uri since its a quick override of class.URI
        req_uri = "%s%s" % (base_uri or self.URI, url)

        if silo:
            # This request has to be sent to a specific "silo" or "subdomain".
            uri = "http://%s%s" % (self.subdomain, req_uri)
            # Don't allow redirects if this is to be sent to a specific silo.
            # For in photobucket's own words..
            # "Photobucket ultimately prefers that you use the information given, rather than relying on the redirects"
            allow_redirects = False
        else:
            uri = "http://%s%s" % (self.DOMAIN, req_uri)
            allow_redirects = True
        req = OAuthRequest.from_consumer_and_token(consumer,
                                                   token,
                                                   method,
                                                   uri,
                                                   parameters=params,
                                                   body=body)

        # Make sure to ALWAYS pass the main domain to the signature instead of the actual url to be requested.
        req.normalized_url = "http://%s%s" % (self.DOMAIN, req_uri)
        req.sign_request(SignatureMethod_HMAC_SHA1(), consumer, token)

        try:
            # I do this to take advantage of the already defined requests and their default values.
            response = getattr(requests,
                               method.lower())(req.to_url(),
                                               headers=headers,
                                               allow_redirects=allow_redirects)
            #response.raise_for_status(allow_redirects=allow_redirects)
        except AttributeError:
            raise PhotobucketAPIError('Invalid Http method')
        except HTTPError, e:
            # This whole handling is still in Beta.
            # Because I'm still deciding on whether to keep it
            # or use "safe_mode" for all "POST" requests. To take advantage of Photobucket's redirect.
            # Suggestions are more than welcome...
            if e.response.status_code == REDIRECT:
                # Need to catch a redirect error because that means that user sent a request
                # without a "silo" so it needs to be stored.
                content = self.parse_response(e.response.content,
                                              params['format'])
                # Not too sure about this...
                self.subdomain = content['content']['subdomain'].split('//')[1]
                return self.make_request(url, base_uri, params, auth, method,
                                         silo, **kwargs)
            error = PhotobucketError(e.message)
            error.response = e.response
            raise error