import itsdangerous import settings jwt = itsdangerous.JSONWebSignatureSerializer(settings.SECRET) def is_valid_hook_key(key): return settings.HOOK_KEY and key == settings.HOOK_KEY def decode_apikey(key): return jwt.loads(key, salt='apikey') def make_apikey(user_id): return jwt.dumps({'user_id': user_id}, salt='apikey').decode()
def post(self, request, msisdn): network = get_network_from_user(request.user) number = models.Number.objects.get(number=msisdn) if (number.network and number.network != network and not request.user.is_staff): return Response("User is not associated with that Number %s %s." % (number.network.pk, network.pk), status=status.HTTP_403_FORBIDDEN) # Must post a valid 'state'. valid_states = ('available', 'released') if request.POST.get('state', None) not in valid_states: return Response("Must post a valid state.", status=status.HTTP_400_BAD_REQUEST) # This is a valid request, begin processing. First check if this is a # number-deactivation request. if (number.state == 'inuse' and request.POST.get('state') == 'available'): # Refuse to deactivate a subscriber's last number. if (len(models.Number.objects.filter(subscriber=number.subscriber)) <= 1): message = ("Cannot deactivate a subscriber's last number." " Instead, delete the subscriber.") return Response(message, status=status.HTTP_400_BAD_REQUEST) # If it's not the subscriber's only number, send an async post to # the BTS to deactivate the number. Sign the request using JWT. bts = number.subscriber.bts url = '%s/config/deactivate_number' % bts.inbound_url data = { 'number': msisdn, # Add a UUID as a nonce for the message. 'msgid': str(uuid.uuid4()), } serializer = itsdangerous.JSONWebSignatureSerializer(bts.secret) signed_data = { 'jwt': serializer.dumps(data), } tasks.async_post.delay(url, signed_data) # Create a 'deactivate_number' UsageEvent. now = datetime.datetime.now(pytz.utc) reason = 'deactivated phone number: %s' % number.number event = models.UsageEvent.objects.create( subscriber=number.subscriber, date=now, bts=bts, kind='deactivate_number', to_number=number.number, reason=reason, oldamt=number.subscriber.balance, newamt=number.subscriber.balance, change=0) event.save() # Diassociate the Number from its former Subscriber and Network. number.subscriber = None number.network = None number.state = request.POST.get('state') number.save() return Response("") # Check if this is a number-release request. if request.POST.get('state') == 'released': # User must be staff to do this. if not request.user.is_staff: return Response("", status=status.HTTP_404_NOT_FOUND) # The number must not be 'inuse.' if number.state == 'inuse': return Response("", status=status.HTTP_400_BAD_REQUEST) # The number cannot be associated with a Sub. if number.subscriber: return Response("", status=status.HTTP_400_BAD_REQUEST) # Validation passes, release (cancel) the number. nexmo_provider = NexmoProvider( settings.ENDAGA['NEXMO_ACCT_SID'], settings.ENDAGA['NEXMO_AUTH_TOKEN'], settings.ENDAGA['NEXMO_INBOUND_SMS_URL'], None, settings.ENDAGA['NEXMO_INBOUND_VOICE_HOST'], country=number.country_id) if nexmo_provider.cancel_number(number.number): # Success, delete the number. number.delete() return Response("", status=status.HTTP_200_OK) else: print 'deleting number %s failed' % number.number return Response("", status=status.HTTP_500_INTERNAL_SERVER_ERROR) # Invalid request. return Response("", status=status.HTTP_400_BAD_REQUEST)
def test_token_is_invalid_if_expiry_time_is_missing(self): bad_s = idmod.JSONWebSignatureSerializer("secret") invalid_token_empty = bad_s.dumps({}) s = self.serializer_class("secret") self.assertRaises(idmod.BadSignature, s.loads, invalid_token_empty)
def __init__(self, app, app_url, client_id=None, secret_key=None, salt=None, authorization_hook=None): Auth.__init__(self, app, authorization_hook) self.config = { 'permissions_cache_expiry': 5 * 60, 'user_cookies_expiry': 604800, # one week. } self._app = app self._app_url = app_url self._oauth_client_id = client_id self._username_cache = {} if secret_key is None and app.server.secret_key is None: raise Exception( dedent(''' app.server.secret_key is missing. Generate a secret key in your Python session with the following commands: >>> import os >>> import base64 >>> base64.b64encode(os.urandom(30)).decode('utf-8') and assign it to the property app.server.secret_key (where app is your dash app instance). Note that you should not do this dynamically: you should create a key and then assign the value of that key in your code. ''')) if salt is None: raise Exception( dedent(''' salt is missing. The salt parameter needs to a string that is unique to this individual Dash app. ''')) self._signer = itsdangerous.TimestampSigner(secret_key, salt=salt) self._json_signer = itsdangerous.JSONWebSignatureSerializer(secret_key, salt=salt) app.server.add_url_rule('{}_dash-login'.format( app.config['routes_pathname_prefix']), view_func=self.login_api, methods=['post']) app.server.add_url_rule('{}_oauth-redirect'.format( app.config['routes_pathname_prefix']), view_func=self.serve_oauth_redirect, methods=['get']) app.server.add_url_rule('{}_is-authorized'.format( app.config['routes_pathname_prefix']), view_func=self.check_if_authorized, methods=['get']) _current_path = os.path.dirname(os.path.abspath(__file__)) # TODO - Dist files with open(os.path.join(_current_path, 'oauth-redirect.js'), 'r') as f: self.oauth_redirect_bundle = f.read() with open(os.path.join(_current_path, 'login.js'), 'r') as f: self.login_bundle = f.read()