def assign_token_to_session(self): token = self.token if token and "oauth_token" in token and "oauth_token_secret" in token: # This really, really violates the Law of Demeter, but # I don't see a better way to set these parameters. :( self.session.auth.client.resource_owner_key = to_unicode(token["oauth_token"]) self.session.auth.client.resource_owner_secret = to_unicode(token["oauth_token_secret"])
def authenticate_client(self, request, *args, **kwargs): auth = request.headers.get('Authorization', None) log.debug('Authenticate client %r', auth) if auth: try: _, s = auth.split(' ') client_id, client_secret = decode_base64(s).split(':') client_id = to_unicode(client_id, 'utf-8') client_secret = to_unicode(client_secret, 'utf-8') except Exception as e: log.debug('Authenticate client failed with exception: %r', e) return False else: client_id = request.client_id client_secret = request.client_secret client = self._clientgetter(client_id) if not client: return False if client.client_secret != client_secret: log.debug('Authenticate client failed, secret not match.') return False request.client = client log.debug('Authenticate client success.') return True
def authenticate_client(self, request, *args, **kwargs): """Authenticate itself in other means. Other means means is described in `Section 3.2.1`_. .. _`Section 3.2.1`: http://tools.ietf.org/html/rfc6749#section-3.2.1 """ auth = request.headers.get('Authorization', None) log.debug('Authenticate client %r', auth) if auth: try: _, s = auth.split(' ') client_id, client_secret = decode_base64(s).split(':') client_id = to_unicode(client_id, 'utf-8') client_secret = to_unicode(client_secret, 'utf-8') except Exception as e: log.debug('Authenticate client failed with exception: %r', e) return False else: client_id = request.client_id client_secret = request.client_secret client = self._clientgetter(client_id) if not client: log.debug('Authenticate client failed, client not found.') return False request.client = client if client.client_secret != client_secret: log.debug('Authenticate client failed, secret not match.') return False log.debug('Authenticate client success.') return True
def authenticate_client(self, request, *args, **kwargs): """Whichever authentication method suits you, HTTP Basic might work.""" auth = request.headers.get('Authorization', None) if auth: auth_type, s = auth.split(' ') if auth_type != 'Basic': return False client_id, client_secret = decode_base64(s).split(':') client_id = to_unicode(client_id, 'utf-8') client_secret = to_unicode(client_secret, 'utf-8') else: client_id = getattr(request, 'client_id', None) client_secret = getattr(request, 'client_secret', None) if client_id is None or client_secret is None: return False client = self.get_client(client_id) if not client: return False request.client = client request.client_id = client_id # oauthlib expect the client to has a client_id attribute request.client.client_id = client_id if client.secret != client_secret: return False # if client.client_type != 'confidential': # return False return True
def load_token(self): t = self.token if t and "oauth_token" in t and "oauth_token_secret" in t: # This really, really violates the Law of Demeter, but # I don't see a better way to set these parameters. :( self.auth.client.resource_owner_key = to_unicode(t["oauth_token"]) self.auth.client.resource_owner_secret = to_unicode(t["oauth_token_secret"]) return True return False
def request(self, method, url, data=None, headers=None, **kwargs): t = self.token if t and "oauth_token" in t and "oauth_token_secret" in t: # This really, really violates the Law of Demeter, but # I don't see a better way to set these parameters. :( self.auth.client.resource_owner_key = to_unicode(t["oauth_token"]) self.auth.client.resource_owner_secret = to_unicode(t["oauth_token_secret"]) return super(OAuth1Session, self).request( method=method, url=url, data=data, headers=headers, **kwargs )
def authenticate_client(self, request, *args, **kwargs): """Authenticate client through means outside the OAuth 2 spec. Means of authentication is negotiated beforehand and may for example be `HTTP Basic Authentication Scheme`_ which utilizes the Authorization header. Headers may be accesses through request.headers and parameters found in both body and query can be obtained by direct attribute access, i.e. request.client_id for client_id in the URL query. :param request: oauthlib.common.Request :rtype: True or False Method is used by: - Authorization Code Grant - Resource Owner Password Credentials Grant (may be disabled) - Client Credentials Grant - Refresh Token Grant .. _`HTTP Basic Authentication Scheme`: http://tools.ietf.org/html/rfc1945#section-11.1 # noqa """ auth = request.headers.get('Authorization', None) log.debug('Authenticate client %r', auth) if auth: try: _, s = auth.split(' ') client_id, client_secret = decode_base64(s).split(':') client_id = to_unicode(client_id, 'utf-8') client_secret = to_unicode(client_secret, 'utf-8') except Exception as e: log.debug('Authenticate client failed with exception: %r', e) return False else: client_id = request.client_id client_secret = request.client_secret client = self._clientgetter(client_id) if not client: return False if client.client_secret != client_secret: log.debug('Authenticate client failed, secret not match.') return False request.client = client log.debug('Authenticate client success.') return True
def __init__(self, client_key, client_secret=None, resource_owner_key=None, resource_owner_secret=None, callback_uri=None, signature_method=SIGNATURE_HMAC, signature_type=SIGNATURE_TYPE_AUTH_HEADER, rsa_key=None, verifier=None, realm=None, encoding='utf-8', nonce=None, timestamp=None): # Convert to unicode using encoding if given, else assume unicode encode = lambda x: to_unicode(x, encoding) if encoding else x self.client_key = encode(client_key) self.client_secret = encode(client_secret) self.resource_owner_key = encode(resource_owner_key) self.resource_owner_secret = encode(resource_owner_secret) self.signature_method = encode(signature_method) self.signature_type = encode(signature_type) self.callback_uri = encode(callback_uri) self.rsa_key = encode(rsa_key) self.verifier = encode(verifier) self.realm = encode(realm) self.encoding = encode(encoding) self.nonce = encode(nonce) self.timestamp = encode(timestamp) if self.signature_method == SIGNATURE_RSA and self.rsa_key is None: raise ValueError('rsa_key is required when using RSA signature method.')
def test_authenticate_client_headers_good(self): rv, request = self._create_request_validator() credentials = "%s:%s" % (self.app_id, self.app_secret) auth = to_unicode(base64.b64encode(credentials.encode('utf-8')), 'utf-8') request.headers['Authorization'] = 'Basic ' + auth self.assertTrue(rv.authenticate_client(request))
def _missing_error(r): token = loads(r.text) if 'errors' in token: # Set the error to the first one we have token['error'] = token['errors'][0]['errorType'] r._content = to_unicode(dumps(token)).encode('UTF-8') return r
def _missing_error(r): token = loads(r.text) if "errors" in token: # Set the error to the first one we have token["error"] = token["errors"][0]["errorType"] r._content = to_unicode(dumps(token)).encode("UTF-8") return r
def get_request_token( self, base_auth_url=None, callback_url=None, auto_set_token=True, **kwargs ): if callback_url: self.session._client.client.callback_uri = \ to_unicode(callback_url, 'utf-8') try: token = self.session.fetch_request_token(self.request_token_url) except requests.RequestException as e: raise TwitterClientError(str(e)) except ValueError as e: raise TwitterClientError('Response does not contain a token.') if base_auth_url: token['auth_url'] = self.session.authorization_url( base_auth_url, **kwargs ) if auto_set_token: self.auto_set_token(token) return JSONObject(token)
def request_request_token(request): """ Checks provided client key and secret and assigns request token if all goes well. """ server = DjangoOAuthServer() if request.method == 'POST': try: is_request_valid = server.verify_request_token_request(uri=request.build_absolute_uri(), headers=request.META)[0] except ValueError as exception: return HttpResponse(exception, status=400) else: if not is_request_valid: return HttpResponse(status=401) headers = collect_parameters(headers=to_unicode(request.META, 'utf-8')) client_key = dict(headers)[u'oauth_consumer_key'] client = Client.objects.get(key=client_key) token = Token.objects.create_request_token(client) token_response = urlencode((('oauth_token', token.key), ('oauth_token_secret', token.secret))) return HttpResponse(token_response, status=200, content_type='application/x-www-form-urlencoded') return HttpResponseNotAllowed('POST', _('Only POST is allowed for this URI.'))
def test_id_site_callback_handler(self): _, acc = self.create_account(self.app.accounts) now = datetime.datetime.utcnow() try: irt = uuid4().get_hex() except AttributeError: irt = uuid4().hex fake_jwt_data = { 'exp': now + datetime.timedelta(seconds=3600), 'aud': self.app._client.auth.id, 'irt': irt, 'iss': 'Stormpath', 'sub': acc.href, 'isNewSub': False, 'state': None, } fake_jwt = to_unicode(jwt.encode( fake_jwt_data, self.app._client.auth.secret, 'HS256'), 'UTF-8') fake_jwt_response = 'http://localhost/?jwtResponse=%s' % fake_jwt ret = self.app.handle_id_site_callback(fake_jwt_response) self.assertIsNotNone(ret) self.assertEqual(ret.account.href, acc.href) self.assertIsNone(ret.state)
def _generate_signed_token(request): client_id = request.client.client_id request.app.api_keys.get_key(client_id) # the SP ApiKey is already validated in SPOauth2RequestValidator.validate_client_id # but to prevent time based attacks oauthlib always goes through the entire # flow even though the entire request will be deemed invalid # in the end. secret = request.app._client.auth.secret now = datetime.datetime.utcnow() data = { 'iss': request.app.href, 'sub': client_id, 'iat': now, 'exp': now + datetime.timedelta(seconds=request.expires_in) } if hasattr(request, 'scope'): data['scope'] = request.scope token = jwt.encode(data, secret, 'HS256') token = to_unicode(token, "UTF-8") return token
def login(self): callback_uri = url_for( ".authorized", next=request.args.get('next'), _external=True, ) self.session._client.client.callback_uri = to_unicode(callback_uri) flask_session['request_token'] = None try: request_token = self.session.fetch_request_token(self.request_token_url) flask_session['request_token'] = request_token except TokenRequestDenied as err: message = err.args[0] response = getattr(err, "response", None) log.warning("OAuth 1 request token error: %s", message) oauth_error.send(self, message=message, response=response) # can't proceed with OAuth, have to just redirect to next_url if "next" in request.args: next_url = request.args["next"] elif self.redirect_url: next_url = self.redirect_url elif self.redirect_to: next_url = url_for(self.redirect_to) else: next_url = "/" return redirect(next_url) url = self.session.authorization_url(self.authorization_url) return redirect(url)
def get_access_token(self, oauth_verifier, auto_set_token=True): required = (self.access_token, self.access_token_secret) if not all(required): raise TwitterClientError( '{} must be initialized with access_token and ' 'access_token_secret to fetch authorized ' 'access token.'.format( self.__class__.__name__ ) ) self.session._client.client.verifier = \ to_unicode(oauth_verifier, 'utf-8') try: token = self.session.fetch_access_token(self.access_token_url) except requests.RequestException as e: raise TwitterClientError(str(e)) except ValueError: raise TwitterClientError('Reponse does not contain a token.') if auto_set_token: self.auto_set_token(token) return JSONObject(token)
def test_id_site_callback_handler_with_major_clock_skew(self): _, acc = self.create_account(self.app.accounts) now = datetime.datetime.utcnow() try: irt = uuid4().get_hex() except AttributeError: irt = uuid4().hex fake_jwt_data = { 'jti': '6S2TKhkW60uYNhcXLThyPo', 'aud': self.app._client.auth.id, 'irt': irt, 'sub': acc.href, 'isNewSub': False, 'state': None, 'exp': now + datetime.timedelta(seconds=3600), 'iat': now + datetime.timedelta(seconds=20), 'iss': 'Stormpath', } fake_jwt = to_unicode(jwt.encode( fake_jwt_data, self.app._client.auth.secret, 'HS256'), 'UTF-8') fake_jwt_response = 'http://localhost/?jwtResponse=%s' % fake_jwt with self.assertRaises(jwt.InvalidIssuedAtError): self.app.handle_stormpath_callback(fake_jwt_response)
def authenticate(self, headers, http_method='', uri='', body=None, scopes=None, ttl=DEFAULT_TTL): """Method that authenticates an HTTP request. :rtype: :class:`stormpath.api_auth.ApiAuthenticationResult` :returns: result if request is valid, `None` otherwise. """ headers = {k: to_unicode(v, 'ascii') for k, v in headers.items()} if body is None: body = {} if scopes is None: scopes = [] auth_scheme, jwt_token = self._get_scheme_and_token( headers, http_method, uri, body, scopes, ttl) access_token = None if jwt_token: access_token = AccessToken(self.app, jwt_token) valid, result = self._authenticate_request( auth_scheme, scopes, http_method, uri, body, headers, ttl) if not valid: return None return ApiAuthenticationResult( account=result.account, api_key=result.api_key, access_token=access_token)
def setUp(self): super(IDSiteCallbackTest, self).setUp() self.store = MagicMock() self.store.get_resource.return_value = {'href': 'acchref', 'sp_http_status': 200} self.store._cache_get.return_value = False # ignore nonce self.client.data_store = self.store self.app = Application( client=self.client, properties={'href': 'apphref', 'accounts': {'href': 'acchref'}}) self.acc = MagicMock(href='acchref') now = datetime.datetime.utcnow() try: irt = uuid4().get_hex() except AttributeError: irt = uuid4().hex fake_jwt_data = { 'exp': now + datetime.timedelta(seconds=3600), 'aud': self.app._client.auth.id, 'irt': irt, 'iss': 'Stormpath', 'sub': self.acc.href, 'isNewSub': False, 'state': None, } self.fake_jwt = to_unicode(jwt.encode( fake_jwt_data, self.app._client.auth.secret, 'HS256'), 'UTF-8')
def __init__( self, client_key, client_secret=None, resource_owner_key=None, resource_owner_secret=None, callback_uri=None, signature_method=SIGNATURE_HMAC, signature_type=SIGNATURE_TYPE_AUTH_HEADER, rsa_key=None, verifier=None, realm=None, encoding="utf-8", decoding=None, nonce=None, timestamp=None, ): """Create an OAuth 1 client. :param client_key: Client key (consumer key), mandatory. :param resource_owner_key: Resource owner key (oauth token). :param resource_owner_secret: Resource owner secret (oauth token secret). :param callback_uri: Callback used when obtaining request token. :param signature_method: SIGNATURE_HMAC, SIGNATURE_RSA or SIGNATURE_PLAINTEXT. :param signature_type: SIGNATURE_TYPE_AUTH_HEADER (default), SIGNATURE_TYPE_QUERY or SIGNATURE_TYPE_BODY depending on where you want to embed the oauth credentials. :param rsa_key: RSA key used with SIGNATURE_RSA. :param verifier: Verifier used when obtaining an access token. :param realm: Realm (scope) to which access is being requested. :param encoding: If you provide non-unicode input you may use this to have oauthlib automatically convert. :param decoding: If you wish that the returned uri, headers and body from sign be encoded back from unicode, then set decoding to your preferred encoding, i.e. utf-8. :param nonce: Use this nonce instead of generating one. (Mainly for testing) :param timestamp: Use this timestamp instead of using current. (Mainly for testing) """ # Convert to unicode using encoding if given, else assume unicode encode = lambda x: to_unicode(x, encoding) if encoding else x self.client_key = encode(client_key) self.client_secret = encode(client_secret) self.resource_owner_key = encode(resource_owner_key) self.resource_owner_secret = encode(resource_owner_secret) self.signature_method = encode(signature_method) self.signature_type = encode(signature_type) self.callback_uri = encode(callback_uri) self.rsa_key = encode(rsa_key) self.verifier = encode(verifier) self.realm = encode(realm) self.encoding = encode(encoding) self.decoding = encode(decoding) self.nonce = encode(nonce) self.timestamp = encode(timestamp) if self.signature_method == SIGNATURE_RSA and self.rsa_key is None: raise ValueError("rsa_key is required when using RSA signature method.")
def decorated(*args, **kwargs): auth = request.headers.get('Authorization', None) if not auth: raise NotConfidential() try: _, s = auth.split(' ') client_id, client_secret = decode_base64(s).split(':') client_id = to_unicode(client_id, 'utf-8') client_secret = to_unicode(client_secret, 'utf-8') except: raise NotConfidential() client = oauth._clientgetter(client_id) if not client or client.client_secret != client_secret: raise NotConfidential() if not client.is_confidential: raise NotConfidential() return f(*args, **kwargs)
def extract_client_data(self): """Helper method for extracting client ID and secret from the authorization header. """ _, b64encoded_data = self.authorization.split(' ') decoded_data = to_unicode( base64.b64decode(b64encoded_data.encode('utf-8')), 'ascii') self.client_id, self.client_secret = decoded_data.split(':')
def login(self): callback_uri = url_for( ".authorized", next=request.args.get('next'), _external=True, ) self.session._client.client.callback_uri = to_unicode(callback_uri) self.session.fetch_request_token(self.request_token_url) url = self.session.authorization_url(self.authorization_url) return redirect(url)
def _compliance_fix(r): if r.status_code != 200: return r token = r.json() expires_in = token.get("expires_in") if expires_in and int(expires_in) < 1: token.pop("expires_in") r._content = to_unicode(dumps(token)).encode("UTF-8") return r
def login(self): secure = request.is_secure or request.headers.get("X-Forwarded-Proto", "http") == "https" callback_uri = url_for( ".authorized", next=request.args.get('next'), _external=True, _scheme="https" if secure else "http", ) self.session._client.client.callback_uri = to_unicode(callback_uri) self.session.fetch_request_token(self.request_token_url) url = self.session.authorization_url(self.authorization_url) return redirect(url)
def _compliance_fix(r): # Plenty returns the Token in CamelCase instead of _ if 'application/json' in r.headers.get('content-type', {}) and r.status_code == 200: token = loads(r.text) else: return r fixed_token = {} for k, v in token.items(): fixed_token[_to_snake_case(k)] = v r._content = to_unicode(dumps(fixed_token)).encode('UTF-8') return r
def authenticate_client(self, request, *args, **kwargs): request.app = self.app request.expires_in = self.ttl authorization = request.headers.get('Authorization') try: auth_scheme, b64encoded_data = authorization.split(' ') decoded_data = to_unicode( base64.b64decode(b64encoded_data.encode('utf-8')), 'ascii') client_id, _ = decoded_data.split(':') request.client = Oauth2BackendApplicationClient(client_id) except Exception: return False if self.validate_client_id(client_id, request): return True return False
def build_id_site_redirect_url(self, callback_uri, path=None, state=None, logout=False): """Builds a redirect uri for ID site. :param callback_uri: Callback URI to witch Stormpaath will redirect after the user has entered their credentials on the ID site. Note: For security reasons this is required to be the same as "Authorized Redirect URI" in the Admin Console's ID Site settings. :param path: An optional string indicating to wich template we should redirect the user to. By default it will redirect to the login screen but you can redirect to the registration or forgot password screen with '/#/register' and '/#/forgot' respectively. :param state: an optional string that stores information that your application needs after the user is redirected back to your application :param logout: a Boolean value indicating if this should redirect to the logout endpoint :return: A URI to witch to redirect the user. """ import jwt from oauthlib.common import to_unicode api_key_secret = self._client.auth.secret api_key_id = self._client.auth.id endpoint = self.SSO_LOGOUT_ENDPOINT if logout else self.SSO_ENDPOINT try: irt = uuid4().get_hex() except AttributeError: irt = uuid4().hex body = { 'iat': datetime.utcnow(), 'jti': irt, 'iss': api_key_id, 'sub': self.href, 'cb_uri': callback_uri, } if path: body['path'] = path if state: body['state'] = state jwt_signature = to_unicode(jwt.encode(body, api_key_secret, 'HS256'), 'UTF-8') url_params = {'jwtRequest': jwt_signature} return endpoint + '?' + urlencode(url_params)
def prepare_request_body(self, private_key=None, subject=None, issuer=None, audience=None, expires_at=None, issued_at=None, extra_claims=None, body='', scope=None, **kwargs): key = private_key or self.private_key if not key: raise ValueError( "Encryption key must be supplied to make JWT token requests." ) claim = { "iss": issuer or self.issuer, "aud": audience or self.audience, "sub": subject, "exp": int(expires_at or time.time() + 3600), "iat": int(issued_at or time.time()), "scope": scope, } for attr in {"iss", "aud"}: if claim[attr] is None: raise ValueError( "Claim must include {} but none was given.".format(attr) ) if "not_before" in kwargs: claim["nbf"] = kwargs.pop("not_before") if "jwt_id" in kwargs: claim["jti"] = kwargs.pop("jwt_id") claim.update(extra_claims or {}) assertion = jwt.encode(claim, key, "RS256") assertion = to_unicode(assertion) return prepare_token_request(self.grant_type, body=body, assertion=assertion, **kwargs)
def _encode(text, encoding='utf-8'): if encoding: return to_unicode(text, encoding) return text
def dummy_client(self): return to_unicode('dummy_client', 'utf-8')