def test_that_macauth_can_use_per_node_hostname_secrets(self): with tempfile.NamedTemporaryFile() as sf: # Write some secrets to a file. sf.write("host1,0001:secret11,0002:secret12\n") sf.write("host2,0001:secret21,0002:secret22\n") sf.flush() # Configure the plugin to load them. config2 = pyramid.testing.setUp() config2.add_settings(self.DEFAULT_SETTINGS) config2.add_settings({ "who.plugin.macauth.secrets_file": sf.name, }) config2.include("mozsvc.user.whoauth") config2.commit() # It should accept a request signed with the old secret on host1. req = self._make_request(config=config2, environ={ "HTTP_HOST": "host1", }) id = tokenlib.make_token({"userid": 42}, secret="secret11") key = tokenlib.get_token_secret(id, secret="secret11") macauthlib.sign_request(req, id, key) self.assertEquals(authenticated_userid(req), 42) # It should accept a request signed with the new secret on host1. req = self._make_request(config=config2, environ={ "HTTP_HOST": "host1", }) id = tokenlib.make_token({"userid": 42}, secret="secret12") key = tokenlib.get_token_secret(id, secret="secret12") macauthlib.sign_request(req, id, key) self.assertEquals(authenticated_userid(req), 42) # It should reject a request signed with secret from other host. req = self._make_request(config=config2, environ={ "HTTP_HOST": "host2", }) id = tokenlib.make_token({"userid": 42}, secret="secret12") key = tokenlib.get_token_secret(id, secret="secret12") macauthlib.sign_request(req, id, key) self.assertRaises(Exception, authenticated_userid, req) # It should accept a request signed with the new secret on host2. req = self._make_request(config=config2, environ={ "HTTP_HOST": "host2", }) id = tokenlib.make_token({"userid": 42}, secret="secret22") key = tokenlib.get_token_secret(id, secret="secret22") macauthlib.sign_request(req, id, key) self.assertEquals(authenticated_userid(req), 42) # It should reject unknown hostnames. req = self._make_request(config=config2, environ={ "HTTP_HOST": "host3", }) id = tokenlib.make_token({"userid": 42}, secret="secret12") key = tokenlib.get_token_secret(id, secret="secret12") macauthlib.sign_request(req, id, key) self.assertRaises(Exception, authenticated_userid, req)
def delete_service_data(user, secret, timeout=60): """Send a data-deletion request to the user's service node. This is a little bit of hackery to cause the user's service node to remove any data it still has stored for the user. We simulate a DELETE request from the user's own account. """ token = tokenlib.make_token( { "uid": user.uid, "node": user.node, "fxa_uid": user.email.split("@", 1)[0], "fxa_kid": format_key_id(user.keys_changed_at or user.generation, binascii.unhexlify(user.client_state)), }, secret=secret) secret = tokenlib.get_derived_secret(token, secret=secret) endpoint = PATTERN.format(uid=user.uid, node=user.node) auth = HawkAuth(token, secret) resp = requests.delete(endpoint, auth=auth, timeout=timeout) if resp.status_code >= 400 and resp.status_code != 404: resp.raise_for_status()
def send_job(repo, server, cycles="", duration="", nodes="", redirect_url=""): mac_user = os.environ.get("MACAUTH_USER") mac_secret = os.environ.get("MACAUTH_SECRET") request = Request.blank(server.rstrip("/") + "/test") request.method = "POST" params = { "repo": repo, "cycles": cycles, "duration": duration, "nodes": nodes, "redirect_url": redirect_url, "api_call": 1, } request.body = urllib.urlencode(params) request.environ["CONTENT_TYPE"] = "application/x-www-form-urlencoded" if mac_user is not None: tokenid = tokenlib.make_token({"user": mac_user}, secret=mac_secret) key = tokenlib.get_token_secret(tokenid, secret=mac_secret) sign_request(request, tokenid, key) resp = request.get_response(proxy_exact_request) if resp.status_int == 401: raise ValueError("Authorization Failed!") job_id = resp.json["job_id"] return server.rstrip("/") + "/test/" + job_id
def delete_service_data(config, service, user, timeout=60): """Send a data-deletion request to the user's service node. This is a little bit of hackery to cause the user's service node to remove any data it still has stored for the user. We simulate a DELETE request from the user's own account. """ secrets = config.registry.settings['tokenserver.secrets'] pattern = config.registry['endpoints_patterns'][service] node_secrets = secrets.get(user.node) if not node_secrets: msg = "The node %r does not have any shared secret" % (user.node,) raise ValueError(msg) token = tokenlib.make_token({ "uid": user.uid, "node": user.node, "fxa_uid": user.email.split("@", 1)[0], "fxa_kid": user.client_state }, secret=node_secrets[-1]) secret = tokenlib.get_derived_secret(token, secret=node_secrets[-1]) endpoint = pattern.format(uid=user.uid, service=service, node=user.node) auth = HawkAuth(token, secret) resp = requests.delete(endpoint, auth=auth, timeout=timeout) if resp.status_code >= 400 and resp.status_code != 404: resp.raise_for_status()
def test_get_token_secret_is_deprecated(self): token = tokenlib.make_token({"hello": "world"}) with warnings.catch_warnings(record=True) as w: warnings.simplefilter("default") tokenlib.get_token_secret(token) self.assertEquals(len(w), 1) self.assertEquals(w[0].category, DeprecationWarning)
def users_create(): response.content_type = 'application/json; charset=utf-8' res = { 'username': request.forms.get('username'), 'password': request.forms.get('password'), 'email': request.forms.get('email') } db = conn.cursor(cursor_factory=psycopg2.extras.DictCursor) secret_token = tokenlib.make_token(res, secret="picoteo grafico") response.status = 200 sql = "INSERT INTO users (username, email, password, session_token) " sql += "VALUES ('%s', '%s', '%s', '%s')" % (res['username'], res['email'], res['password'], secret_token) db.execute(sql) conn.commit() db.close() return { 'status': 'success', 'data': { 'message': 'user created', 'session_token': secret_token } }
def login_method(request): if request.method != "POST": return HttpResponseNotAllowed(permitted_methods=['POST']) username = request.POST.get(POST_USERNAME) password = request.POST.get(POST_PASSWORD) user = authenticate(username=username, password=password) if user is not None: if user.is_active: login(request, user) # get or make secret for token if unique_token_key.objects.all().count() == 0: randomString = str(random.randint(0, 32767)) secret = randomString uniqueObject = unique_token_key(key_id=1, key=randomString) uniqueObject.save() else: secret = unique_token_key.objects.get(pk=1).key token = tokenlib.make_token({"userid": user.id}, secret=secret) template = loader.get_template('CPBet/homepage.html') context = RequestContext(request, {TOKEN: token}) return HttpResponse(template.render(context)) else: return HttpResponse(json.dumps({"Status": STATUS_WRONG_USERNAME_OR_PASSWORD, "Error": "Username or password incorrect."}, sort_keys=True))
def send_job(repo, server, cycles='', duration='', nodes='', redirect_url=''): mac_user = os.environ.get('MACAUTH_USER') mac_secret = os.environ.get('MACAUTH_SECRET') request = Request.blank(server.rstrip('/') + '/test') request.method = 'POST' params = { 'repo': repo, 'cycles': cycles, 'duration': duration, 'nodes': nodes, 'redirect_url': redirect_url, 'api_call': 1 } request.body = urllib.urlencode(params) request.environ['CONTENT_TYPE'] = 'application/x-www-form-urlencoded' if mac_user is not None: tokenid = tokenlib.make_token({"user": mac_user}, secret=mac_secret) key = tokenlib.get_token_secret(tokenid, secret=mac_secret) sign_request(request, tokenid, key) resp = request.get_response(proxy_exact_request) if resp.status_int == 401: raise ValueError("Authorization Failed!") job_id = resp.json['job_id'] return server.rstrip('/') + '/test/' + job_id
def delete_service_data(config, service, user, timeout=60, settings=None): """Send a data-deletion request to the user's service node. This is a little bit of hackery to cause the user's service node to remove any data it still has stored for the user. We simulate a DELETE request from the user's own account. """ secrets = config.registry.settings['tokenserver.secrets'] pattern = config.registry['endpoints_patterns'][service] node_secrets = secrets.get(user.node) if not node_secrets: msg = "The node %r does not have any shared secret" % (user.node, ) raise ValueError(msg) token = tokenlib.make_token( { "uid": user.uid, "node": user.node, "fxa_uid": user.email.split("@", 1)[0], "fxa_kid": format_key_id(user.keys_changed_at or user.generation, user.client_state.decode('hex')), }, secret=node_secrets[-1]) secret = tokenlib.get_derived_secret(token, secret=node_secrets[-1]) endpoint = pattern.format(uid=user.uid, service=service, node=user.node) auth = HawkAuth(token, secret) if settings and settings.dryrun: return resp = requests.delete(endpoint, auth=auth, timeout=timeout) if resp.status_code >= 400 and resp.status_code != 404: resp.raise_for_status()
def return_token(request): # at this stage, we are sure that the assertion, application and version # number were valid, so let's build the authentication token and return it. backend = request.registry.getUtility(INodeAssignment) email = request.validated['assertion']['email'] application = request.validated['application'] version = request.validated['version'] pattern = request.validated['pattern'] service = get_service_name(application, version) # get the node or allocate one if none is already set uid, node = backend.get_node(email, service) if node is None or uid is None: uid, node = backend.allocate_node(email, service) secrets = request.registry.settings['tokenserver.secrets_file'] node_secrets = secrets.get(node) if not node_secrets: raise Exception("The specified node does not have any shared secret") secret = node_secrets[-1] # the last one is the most recent one token = make_token({'uid': uid, 'service_entry': node}, secret=secret) # XXX needs to be renamed as 'get_derived_secret' because # it's not clear here it's a derived secret = get_token_secret(token, secret=secret) api_endpoint = pattern.format(uid=uid, service=service, node=node) # FIXME add the algo used to generate the token return {'id': token, 'key': secret, 'uid': uid, 'api_endpoint': api_endpoint}
def test_convenience_functions(self): token = tokenlib.make_token({"hello": "world"}) self.assertEquals(tokenlib.parse_token(token)["hello"], "world") self.assertRaises(ValueError, tokenlib.parse_token, token, secret="X") self.assertEquals(tokenlib.get_token_secret(token), tokenlib.get_token_secret(token)) self.assertNotEquals(tokenlib.get_token_secret(token), tokenlib.get_token_secret(token, secret="X"))
def generate_token(user_id): if tokens_collection.find({"user_id": user_id}).count() == 0: logging.info('creating token...') token = tokenlib.make_token({"user_id": user_id}, secret="I_LIKE_UNICORNS") return token else: logging.info("token exist...") data_token = tokens_collection.find_one({"user_id": user_id}) token = str(data_token['key']) if validate_token(token): return token else: logging.info('token expired...') logging.info('creating a new...') tokens_collection.remove({'_id': data_token['_id']}) token = tokenlib.make_token({"user_id": user_id}, secret="I_LIKE_UNICORNS") return token
def test_invalid_callurl_token_returns_400(self): # Let's forge a call token with an invalid secret. invalid_token = tokenlib.make_token({'userid': 'h4x0r'}, secret='I AM MEAN') resp = self.app.get('/calls/%s' % invalid_token, status=400) self.assertEquals(resp.json['status'], 'error') self.assertEquals(resp.json['errors'][0]['description'], 'token has invalid signature')
def veryfi(self,username,password): if username=="123123" and password == "123123": token_ram = tokenlib.make_token({"user":username})[:10] # token太长,有时gw会截断,重新生成,导致认证失败 tok[username] = token_ram raise cherrypy.HTTPRedirect("http://172.16.100.1:8060/wifidog/auth?token=%s"%token_ram,status=302) else: return "wrong user or passwd!"
def _generate_token_credentials(self): """Pick an identity, log in and generate the auth token.""" # If the server_url has a hash fragment, it's a storage node and # that's the secret. Otherwise it's a token server url. uid = random.randint(1, 1000000) url = urlparse(self.server_url) if url.fragment: endpoint = url._replace(fragment="", path="/1.5/" + str(uid)) self.endpoint_url = urlunparse(endpoint) data = { "uid": uid, "node": urlunparse(url._replace(fragment="")), "expires": time.time() + ASSERTION_LIFETIME, } self.auth_token = tokenlib.make_token(data, secret=url.fragment) self.auth_secret = tokenlib.get_derived_secret(self.auth_token, secret=url.fragment) else: email = "user%s@%s" % (uid, MOCKMYID_DOMAIN) exp = time.time() + ASSERTION_LIFETIME + HawkAuth.timeskew assertion = browserid.tests.support.make_assertion( email=email, audience=self.server_url, issuer=MOCKMYID_DOMAIN, issuer_keypair=(None, MOCKMYID_PRIVATE_KEY), exp=int(exp * 1000), ) token_url = self.server_url + "/1.0/sync/1.5" response = self.session.get(token_url, headers={ "Authorization": "BrowserID " + assertion, }) # Maybe timeskew between client and server? if response.status_code == 401: server_time = int(response.headers["X-Timestamp"]) HawkAuth.timeskew = server_time - int(time.time()) exp = time.time() + ASSERTION_LIFETIME + HawkAuth.timeskew assertion = browserid.tests.support.make_assertion( email=email, audience=self.server_url, issuer=MOCKMYID_DOMAIN, issuer_keypair=(None, MOCKMYID_PRIVATE_KEY), exp=int(exp * 1000), ) response = self.session.get(token_url, headers={ "Authorization": "BrowserID " + assertion, }) response.raise_for_status() credentials = response.json() self.auth_token = credentials["id"].encode('ascii') self.auth_secret = credentials["key"].encode('ascii') self.endpoint_url = credentials["api_endpoint"] return self.auth_token, self.auth_secret, self.endpoint_url
def test_valid_oauth_request(self): oauth_token = self.oauth_token headers = { 'Authorization': 'Bearer %s' % oauth_token, 'X-KeyID': '1234-qqo' } # Send a valid request, allocating a new user res = self.app.get('/1.0/sync/1.5', headers=headers) fxa_uid = self.session.uid # Retrieve the user from the database user = self._get_user(res.json['uid']) # First, let's verify that the token we received is valid. To do this, # we can unpack the hawk header ID into the payload and its signature # and then construct a tokenlib token to compute the signature # ourselves. To obtain a matching signature, we use the same secret as # is used by Tokenserver. raw = urlsafe_b64decode(res.json['id']) payload = raw[:-32] signature = raw[-32:] payload_dict = json.loads(payload.decode('utf-8')) # The `id` payload should include a field indicating the origin of the # token self.assertEqual(payload_dict['tokenserver_origin'], 'rust') signing_secret = self.TOKEN_SIGNING_SECRET expected_token = tokenlib.make_token(payload_dict, secret=signing_secret) expected_signature = urlsafe_b64decode(expected_token)[-32:] # Using the #compare_digest method here is not strictly necessary, as # this is not a security-sensitive situation, but it's good practice self.assertTrue(hmac.compare_digest(expected_signature, signature)) # Check that the given key is a secret derived from the hawk ID expected_secret = tokenlib.get_derived_secret(res.json['id'], secret=signing_secret) self.assertEqual(res.json['key'], expected_secret) # Check to make sure the remainder of the fields are valid self.assertEqual(res.json['uid'], user['uid']) self.assertEqual(res.json['api_endpoint'], '%s/1.5/%s' % (self.NODE_URL, user['uid'])) self.assertEqual(res.json['duration'], DEFAULT_TOKEN_DURATION) self.assertEqual(res.json['hashalg'], 'sha256') self.assertEqual(res.json['hashed_fxa_uid'], self._fxa_metrics_hash(fxa_uid)[:32]) self.assertEqual(res.json['node_type'], 'spanner') # The response should have an X-Timestamp header that contains the # number of seconds since the UNIX epoch self.assertIn('X-Timestamp', res.headers) self.assertIsNotNone(int(res.headers['X-Timestamp'])) token = self.unsafelyParseToken(res.json['id']) self.assertIn('hashed_device_id', token) self.assertEqual(token["uid"], res.json["uid"]) self.assertEqual(token["fxa_uid"], fxa_uid) self.assertEqual(token["fxa_kid"], "0000000001234-qqo") self.assertNotEqual(token["hashed_fxa_uid"], token["fxa_uid"]) self.assertEqual(token["hashed_fxa_uid"], res.json["hashed_fxa_uid"]) self.assertIn("hashed_device_id", token)
def invite(request, team_id): team = Team.objects.get(team_id=team_id) token = make_token({ "team_id": team_id, "team_name": team.team_name }, timeout=team.moderator_expire, secret=SECRET_SALT) Token(token=token).save() context = {'token': token} return render(request, 'leave_bot/invite.html', context)
def test_valid_browserid_request(self): assertion = self.browserid_assertion headers = { 'Authorization': 'BrowserID %s' % assertion, 'X-Client-State': 'aaaa' } # Send a valid request, allocating a new user res = self.app.get('/1.0/sync/1.5', headers=headers) fxa_uid = self.session.uid # Retrieve the user from the database user = self._get_user(res.json['uid']) # First, let's verify that the token we received is valid. To do this, # we can unpack the hawk header ID into the payload and its signature # and then construct a tokenlib token to compute the signature # ourselves. To obtain a matching signature, we use the same secret as # is used by Tokenserver. raw = urlsafe_b64decode(res.json['id']) payload = raw[:-32] signature = raw[-32:] payload_dict = json.loads(payload.decode('utf-8')) signing_secret = self.TOKEN_SIGNING_SECRET expected_token = tokenlib.make_token(payload_dict, secret=signing_secret) expected_signature = urlsafe_b64decode(expected_token)[-32:] # Using the #compare_digest method here is not strictly necessary, as # this is not a security-sensitive situation, but it's good practice self.assertTrue(hmac.compare_digest(expected_signature, signature)) # Check that the given key is a secret derived from the hawk ID expected_secret = tokenlib.get_derived_secret(res.json['id'], secret=signing_secret) self.assertEqual(res.json['key'], expected_secret) # Check to make sure the remainder of the fields are valid self.assertEqual(res.json['uid'], user['uid']) self.assertEqual(res.json['api_endpoint'], '%s/1.5/%s' % (self.NODE_URL, user['uid'])) self.assertEqual(res.json['duration'], DEFAULT_TOKEN_DURATION) self.assertEqual(res.json['hashalg'], 'sha256') self.assertEqual(res.json['hashed_fxa_uid'], self._fxa_metrics_hash(fxa_uid)[:32]) self.assertEqual(res.json['node_type'], 'spanner') token = self.unsafelyParseToken(res.json['id']) self.assertIn('hashed_device_id', token) self.assertEqual(token["uid"], res.json["uid"]) self.assertEqual(token["fxa_uid"], fxa_uid) assertion = self.browserid_assertion keys_changed_at = \ self._extract_keys_changed_at_from_assertion(assertion) self.assertEqual(token["fxa_kid"], "%s-qqo" % str(keys_changed_at)) self.assertNotEqual(token["hashed_fxa_uid"], token["fxa_uid"]) self.assertEqual(token["hashed_fxa_uid"], res.json["hashed_fxa_uid"]) self.assertIn("hashed_device_id", token)
def _get_public_token(self): """ When asked for a new public token, it will generate a new public key, with a new expiration date """ secret = IAnnotations(self)[SECRET_KEY] public = tokenlib.make_token({}, secret=secret, timeout=TIMEOUT) expiry_date = date.today() + timedelta(seconds=TIMEOUT) IAnnotations(self)[TOKEN_EXPIRES_KEY] = expiry_date IAnnotations(self)[TOKEN_KEY] = public return public
def encode_mac_id(self, request, userid=None, **data): """Encode the given userid into a MACAuth token id and secret key. This method is essentially the reverse of decode_mac_id. Given a userid, it returns a MACAuth id and corresponding secret key. It is not needed for consuming authentication tokens, but is very useful when building them for testing purposes. """ if userid is not None: data["userid"] = userid tokenid = tokenlib.make_token(data, secret=self.master_secret) secret = tokenlib.get_token_secret(tokenid, secret=self.master_secret) return tokenid, secret
def encode_mac_id(self, request, userid): """Encode the given userid into a MAC id and secret key. This method is essentially the reverse of decode_mac_id. It is not needed for consuming authentication tokens, but is very useful when building them for testing purposes. """ # There might be multiple secrets in use, if we're in the # process of transitioning from one to another. Always use # the last one aka the "most recent" secret. secret = self._get_token_secrets(request)[-1] tokenid = tokenlib.make_token({"uid": userid}, secret=secret) key = tokenlib.get_token_secret(tokenid, secret=secret) return tokenid, key
def encode_hawk_id( # pylint: disable=E0202, W0613 self, request, userid=None, **data): """Encode the given userid into a Hawk token id and secret key. This method is essentially the reverse of decode_hawk_id. Given a userid, it returns a Hawk id and corresponding secret key. It is not needed for consuming authentication tokens, but is very useful when building them for testing purposes. """ if userid is not None: data["userid"] = userid master_secret = self.master_secret tokenid = tokenlib.make_token(data, secret=master_secret) secret = tokenlib.get_derived_secret(tokenid, secret=master_secret) return tokenid, secret
def create_token(): expires = int(time.time()) + DURATION token_data = { 'uid': LEGACY_UID, 'node': NODE, 'expires': expires, 'fxa_uid': FXA_UID, 'fxa_kid': FXA_KID, 'hashed_fxa_uid': metrics_hash(FXA_UID), 'hashed_device_id': metrics_hash(DEVICE_ID), 'salt': SALT, } token = tokenlib.make_token(token_data, secret=SECRET) key = tokenlib.get_derived_secret(token, secret=SECRET) return token, key, expires, SALT
def encode_hawk_id(self, request, data): """Encode data dict into Hawk id token and secret key. This method is essentially the reverse of decode_hawk_id. Given a dict of identity data, it encodes it into a unique Hawk id token and corresponding secret key. By default it uses the tokenlib library, but plugin instances may override this method with another callable the config file. This method is not needed when consuming auth tokens, but is very handy when building them for testing purposes. """ id = tokenlib.make_token(data, secret=self.master_secret) secret = tokenlib.get_token_secret(id, secret=self.master_secret) return id, secret
def create_token(args): expires = int(time.time()) + args.duration token_data = { 'uid': args.uid, 'node': args.node, 'expires': expires, 'fxa_uid': args.fxa_uid, 'fxa_kid': args.fxa_kid, 'hashed_fxa_uid': metrics_hash(args, args.fxa_uid), 'hashed_device_id': metrics_hash(args, args.device_id), 'salt': SALT, } token = tokenlib.make_token(token_data, secret=args.secret) key = tokenlib.get_derived_secret(token, secret=args.secret) return token, key, expires, SALT
def encode_hawk_id(self, request, userid, extra=None): """Encode the given userid into a Hawk id and secret key. This method is essentially the reverse of decode_hawk_id. It is not needed for consuming authentication tokens, but is very useful when building them for testing purposes. """ node_name = self._get_node_name(request) # There might be multiple secrets in use, if we're in the # process of transitioning from one to another. Always use # the last one aka the "most recent" secret. secret = self._get_token_secrets(node_name)[-1] data = {"uid": userid, "node": node_name} if extra is not None: data.update(extra) tokenid = tokenlib.make_token(data, secret=secret) key = tokenlib.get_derived_secret(tokenid, secret=secret) return tokenid, key
def encode_hawk_id(self, request, userid, extra=None): """Encode the given userid into a Hawk id and secret key. This method is essentially the reverse of decode_hawk_id. It is not needed for consuming authentication tokens, but is very useful when building them for testing purposes. Unlike its superclass method, this one allows the caller to specify a dict of additional user data to include in the auth token. """ node_name = self._get_node_name(request) secret = self._get_token_secrets(node_name)[-1] data = {"uid": userid, "node": node_name} if extra is not None: data.update(extra) tokenid = tokenlib.make_token(data, secret=secret) key = tokenlib.get_derived_secret(tokenid, secret=secret) return tokenid, key
def login(): data = json.loads(flask.request.data) try: managers.email_password_correct(data) except managers.Incorrect as exc: abort(str(exc), 400) control = controller.Controller(flask.current_app.config) try: user_id = control.login(data["email"], data["password"]) except managers.NotFound as exc: abort(str(exc), 401) except managers.NotActive as exc: abort(str(exc), 400) except managers.SecurityError as exc: abort(str(exc), 401) token = tokenlib.make_token( {"user_id": user_id}, secret=flask.current_app.config["security"]["key"]) return flask.jsonify({"token": token}), 200
def register_method(request): if request.method != "POST": return HttpResponseNotAllowed(permitted_methods=['POST']) # make sure u verify that the 2 passwords are the same username = request.POST.get(POST_USERNAME) password = request.POST.get(POST_PASSWORD) email = request.POST.get(POST_EMAIL) try: # we create the User object new_user = User.objects.create_user( username=username, password=password, email=email, ) new_user.save() except: return HttpResponse(json.dumps({"Status": STATUS_DUPLICATE, "Error": "User could not be created. Duplicate username or email"}, sort_keys=True)) # authenticate newly formed user # is it possible to use new_user references???? user = authenticate(username=username, password=password) if user is not None: if user.is_active: # we log in and create token login(request, user) print "User has been authenticated." # get or make secret for token if unique_token_key.objects.all().count() == 0: randomString = str(random.randint(0, 32767)) secret = randomString uniqueObject = unique_token_key(key_id=1, key=randomString) uniqueObject.save() else: secret = unique_token_key.objects.get(pk=1).key token = tokenlib.make_token({"userid": user.id}, secret=secret) template = loader.get_template('CPBet/homepage.html') context = RequestContext(request, {TOKEN: token}) return HttpResponse(template.render(context)) else: return HttpResponse(json.dumps({"Status": STATUS_NOT_YET, "Error": "The account has not been created yet."}, sort_keys=True))
def login_user(): email = request.form['email'] password = request.form['password'] errors = {} print(email, password) if find_userbyEmail(email) is not None: from models.users import User user = db.session.query(User).filter_by(email=email).first() if user.password == password: token = tokenlib.make_token({ "id": user.id, "admin": user.admin }, secret=super_duper_secret, timeout=60 * 60) from models.users import Profile prof = db.session.query(Profile).filter_by(user_id=user.id).first() if user.admin == True: print("admin", user) return json.dumps({ "success": True, "token": token, "profile_url": "/admin_page", "errors": errors }) print("Normal user", user) return json.dumps({ "success": True, "token": token, "profile_url": "/profile/{0}.{1}".format(prof.name, prof.surname), "errors": errors }) else: errors['password'] = "******" return json.dumps({"success": False, "errors": errors}) else: print("email and password worng") errors['email'] = "No user with this email exists" return json.dumps({"success": False, "errors": errors})
def login(self, username: str, password: str): user = User.objects(username=username, password=sha256( password.encode()).hexdigest()).first() if user: token = tokenlib.make_token( { "user_id": str(user.id), 'username': username, 'password': password, 'random_value': random.randint(0, 1000000) }, secret=SECRET_KEY) user.isAuth = True user.token = token user.date_last_login = timezone.now() user.save() return token else: raise UnknownUserError(username)
def delete_service_data(config, service, uid, node, timeout=60): """Send a data-deletion request to the user's service node. This is a little bit of hackery to cause the user's service node to remove any data it still has stored for the user. We simulate a DELETE request from the user's own account. """ secrets = config.registry.settings['tokenserver.secrets'] pattern = config.registry['endpoints_patterns'][service] node_secrets = secrets.get(node) if not node_secrets: msg = "The node %r does not have any shared secret" % (node, ) raise ValueError(msg) user = {"uid": uid, "node": node} token = tokenlib.make_token(user, secret=node_secrets[-1]) secret = tokenlib.get_derived_secret(token, secret=node_secrets[-1]) endpoint = pattern.format(uid=uid, service=service, node=node) auth = HawkAuth(token, secret) resp = requests.delete(endpoint, auth=auth, timeout=timeout) if resp.status_code >= 400 and resp.status_code != 404: resp.raise_for_status()
def send_job(repo, server, cycles='', duration='', nodes='', redirect_url=''): mac_user = os.environ.get('MACAUTH_USER') mac_secret = os.environ.get('MACAUTH_SECRET') request = Request.blank(server.rstrip('/') + '/test') request.method = 'POST' params = {'repo': repo, 'cycles': cycles, 'duration': duration, 'nodes': nodes, 'redirect_url': redirect_url, 'api_call': 1} request.body = urllib.urlencode(params) request.environ['CONTENT_TYPE'] = 'application/x-www-form-urlencoded' if mac_user is not None: tokenid = tokenlib.make_token({"user": mac_user}, secret=mac_secret) key = tokenlib.get_token_secret(tokenid, secret=mac_secret) sign_request(request, tokenid, key) resp = request.get_response(proxy_exact_request) if resp.status_int == 401: raise ValueError("Authorization Failed!") job_id = resp.json['job_id'] return server.rstrip('/') + '/test/' + job_id
#coding:utf-8 #!/usr/bin/env python #Created by Charles on 2018/3/1 import tokenlib import tokenize print (tokenlib.make_token({"user":12},)) def ssx(**kwargs): print(kwargs["ss"]) ssx(**{"ss":21})
def return_token(request): """This service does the following process: - validates the BrowserID assertion provided on the Authorization header - allocates when necessary a node to the user for the required service - checks generation numbers and x-client-state header - returns a JSON mapping containing the following values: - **id** -- a signed authorization token, containing the user's id for hthe application and the node. - **secret** -- a secret derived from the shared secret - **uid** -- the user id for this servic - **api_endpoint** -- the root URL for the user for the service. """ # at this stage, we are sure that the assertion, application and version # number were valid, so let's build the authentication token and return it. backend = request.registry.getUtility(INodeAssignment) settings = request.registry.settings email = request.validated['authorization']['email'] try: idp_claims = request.validated['authorization']['idpClaims'] generation = idp_claims['fxa-generation'] if not isinstance(generation, (int, long)): raise _unauthorized("invalid-generation") except KeyError: generation = 0 application = request.validated['application'] version = request.validated['version'] pattern = request.validated['pattern'] service = get_service_name(application, version) client_state = request.validated['client-state'] with metrics_timer('tokenserver.backend.get_user', request): user = backend.get_user(service, email) if not user: allowed = settings.get('tokenserver.allow_new_users', True) if not allowed: raise _unauthorized('new-users-disabled') with metrics_timer('tokenserver.backend.allocate_user', request): user = backend.allocate_user(service, email, generation, client_state) # Update if this client is ahead of previously-seen clients. updates = {} if generation > user['generation']: updates['generation'] = generation if client_state != user['client_state']: # Don't revert from some-client-state to no-client-state. if not client_state: raise _invalid_client_state('empty string') # Don't revert to a previous client-state. if client_state in user['old_client_states']: raise _invalid_client_state('stale value') # If the IdP has been sending generation numbers, then # don't update client-state without a change in generation number. if user['generation'] > 0 and 'generation' not in updates: raise _invalid_client_state('new value with no generation change') updates['client_state'] = client_state if updates: with metrics_timer('tokenserver.backend.update_user', request): backend.update_user(service, user, **updates) # Error out if this client is behind some previously-seen client. # This is done after the updates because some other, even more up-to-date # client may have raced with a concurrent update. if user['generation'] > generation: raise _unauthorized("invalid-generation") secrets = settings['tokenserver.secrets'] node_secrets = secrets.get(user['node']) if not node_secrets: raise Exception("The specified node does not have any shared secret") secret = node_secrets[-1] # the last one is the most recent one # Clients can request a smaller token duration via an undocumented # query parameter, for testing purposes. token_duration = settings.get( 'tokenserver.token_duration', DEFAULT_TOKEN_DURATION ) try: requested_duration = int(request.params["duration"]) except (KeyError, ValueError): pass else: if 0 < requested_duration < token_duration: token_duration = requested_duration token_data = { 'uid': user['uid'], 'node': user['node'], 'expires': int(time.time()) + token_duration, 'fxa_uid': request.validated['fxa_uid'], 'device_id': request.validated['device_id'] } token = tokenlib.make_token(token_data, secret=secret) secret = tokenlib.get_derived_secret(token, secret=secret) endpoint = pattern.format( uid=user['uid'], service=service, node=user['node'] ) # To help measure user retention, include the timestamp at which we # first saw this user as part of the logs. request.metrics['uid.first_seen_at'] = user['first_seen_at'] return { 'id': token, 'key': secret, 'uid': user['uid'], 'hashed_fxa_uid': request.validated['fxa_uid'], 'api_endpoint': endpoint, 'duration': token_duration, 'hashalg': tokenlib.DEFAULT_HASHMOD }
def _get_credentials(self, **data): id = tokenlib.make_token(data) key = tokenlib.get_token_secret(id) return {"id": id, "key": key}
def return_token(request): """This service does the following process: - validates the BrowserID or OAuth credentials provided in the Authorization header - allocates when necessary a node to the user for the required service - checks generation number, key-rotation timestamp and x-client-state header for consistency - returns a JSON mapping containing the following values: - **id** -- a signed authorization token, containing the user's id for hthe application and the node. - **secret** -- a secret derived from the shared secret - **uid** -- the user id for this service - **api_endpoint** -- the root URL for the user for the service. """ # at this stage, we are sure that the credentials, application and version # number were valid, so let's build the authentication token and return it. backend = request.registry.getUtility(INodeAssignment) settings = request.registry.settings email = request.validated['authorization']['email'] # The `generation` and `keys_changed_at` fields are both optional. try: idp_claims = request.validated['authorization']['idpClaims'] except KeyError: generation = 0 keys_changed_at = 0 else: generation = idp_claims.get('fxa-generation', 0) if not isinstance(generation, (int, long)): raise _unauthorized("invalid-generation") keys_changed_at = idp_claims.get('fxa-keysChangedAt', 0) if not isinstance(keys_changed_at, (int, long)): raise _unauthorized("invalid-credentials", description="invalid keysChangedAt") application = request.validated['application'] version = request.validated['version'] pattern = request.validated['pattern'] service = get_service_name(application, version) client_state = request.validated['client-state'] with metrics_timer('tokenserver.backend.get_user', request): user = backend.get_user(service, email) if not user: allowed = settings.get('tokenserver.allow_new_users', True) if not allowed: raise _unauthorized('new-users-disabled') with metrics_timer('tokenserver.backend.allocate_user', request): user = backend.allocate_user(service, email, generation, client_state, keys_changed_at=keys_changed_at) # We now perform an elaborate set of consistency checks on the # provided claims, which we expect to behave as follows: # # * `generation` is a monotonic timestamp, and increases every time # there is an authentication-related change on the user's account. # # * `keys_changed_at` is a monotonic timestamp, and increases every time # the user's keys change. This is a type of auth-related change, so # `keys_changed_at` <= `generation` at all times. # # * `client_state` is a key fingerprint and should never change back # to a previously-seen value. # # Callers who provide identity claims that violate any of these rules # either have stale credetials (in which case they should re-authenticate) # or are buggy (in which case we deny them access to the user's data). # # The logic here is slightly complicated by the fact that older versions # of the FxA server may not have been sending all the expected fields, and # that some clients do not report the `generation` timestamp. # Update if this client is ahead of previously-seen clients. updates = {} if generation > user['generation']: updates['generation'] = generation if keys_changed_at > user['keys_changed_at']: # If the caller reports a generation number, then a change # in keys should correspond to a change in generation number. # Unfortunately a previous version of the server that didn't # have `keys_changed_at` support may have already seen and # written the new value of `generation`. The best we can do # here is enforce that `keys_changed_at` <= `generation`. if generation > 0 and generation < keys_changed_at: raise _unauthorized('invalid-keysChangedAt') if generation == 0 and keys_changed_at > user['generation']: updates['generation'] = keys_changed_at updates['keys_changed_at'] = keys_changed_at if client_state != user['client_state']: # Don't revert from some-client-state to no-client-state. if not client_state: raise _invalid_client_state('empty string') # Don't revert to a previous client-state. if client_state in user['old_client_states']: raise _invalid_client_state('stale value') # If we have a generation number, then # don't update client-state without a change in generation number. if generation > 0 and 'generation' not in updates: raise _invalid_client_state('new value with no generation change') # If the IdP has been sending keys_changed_at timestamps, then # don't update client-state without a change in keys_changed_at. if user['keys_changed_at'] > 0 and 'keys_changed_at' not in updates: raise _invalid_client_state( 'new value with no keys_changed_at change') updates['client_state'] = client_state if updates: with metrics_timer('tokenserver.backend.update_user', request): backend.update_user(service, user, **updates) # Error out if this client provided a generation number, but it is behind # the generation number of some previously-seen client. if generation > 0 and user['generation'] > generation: raise _unauthorized("invalid-generation") # Error out if we previously saw a keys_changed_at for this user, but they # haven't provided one or it's earlier than previously seen. This means # that once the IdP starts sending keys_changed_at, we'll error out if it # stops (because we can't generate a proper `fxa_kid` in this case). if user['keys_changed_at'] > 0: if user['keys_changed_at'] > keys_changed_at: raise _unauthorized("invalid-keysChangedAt") secrets = settings['tokenserver.secrets'] node_secrets = secrets.get(user['node']) if not node_secrets: raise Exception("The specified node does not have any shared secret") secret = node_secrets[-1] # the last one is the most recent one # Clients can request a smaller token duration via an undocumented # query parameter, for testing purposes. token_duration = settings.get('tokenserver.token_duration', DEFAULT_TOKEN_DURATION) try: requested_duration = int(request.params["duration"]) except (KeyError, ValueError): pass else: if 0 < requested_duration < token_duration: token_duration = requested_duration token_data = { 'uid': user['uid'], 'node': user['node'], 'expires': int(time.time()) + token_duration, 'fxa_uid': request.validated['fxa_uid'], 'fxa_kid': format_key_id( # Follow FxA behaviour of using generation as a fallback. user['keys_changed_at'] or user['generation'], client_state.decode('hex')), 'hashed_fxa_uid': request.validated['hashed_fxa_uid'], 'hashed_device_id': request.validated['hashed_device_id'] } token = tokenlib.make_token(token_data, secret=secret) secret = tokenlib.get_derived_secret(token, secret=secret) endpoint = pattern.format(uid=user['uid'], service=service, node=user['node']) # To help measure user retention, include the timestamp at which we # first saw this user as part of the logs. request.metrics['uid.first_seen_at'] = user['first_seen_at'] # To help segmented analysis of client-side metrics, we can tell # clients to tag their metrics with a "node type" string that is # at much coarser granularity than the individual node name. try: node_type = settings['tokenserver.node_type_classifier'](user['node']) except KeyError: node_type = None request.metrics['node_type'] = node_type return { 'id': token, 'key': secret, 'uid': user['uid'], 'api_endpoint': endpoint, 'duration': token_duration, 'hashalg': tokenlib.DEFAULT_HASHMOD, # Extra stuff for clients to include in telemetry. 'hashed_fxa_uid': request.validated['hashed_fxa_uid'], 'node_type': node_type, }
def test_tokens_are_native_string_type(self): token = tokenlib.make_token({"hello": "world"}) assert isinstance(token, str)
def get_token(user_id): return tokenlib.make_token({'user_id': user_id}, secret='h5j43hl254jl8l7k68')
def test_that_macauth_can_use_per_node_hostname_secrets(self): with tempfile.NamedTemporaryFile() as sf: # Write some secrets to a file. sf.write("http://host1.com,0001:secret11,0002:secret12\n") sf.write("https://host2.com,0001:secret21,0002:secret22\n") sf.write("https://host3.com:444,0001:secret31,0002:secret32\n") sf.flush() # Configure the plugin to load them. config2 = pyramid.testing.setUp() config2.add_settings(DEFAULT_SETTINGS) config2.add_settings({ "macauth.secrets_file": sf.name, }) config2.include("mozsvc.user") config2.commit() # It should accept a request signed with the old secret on host1. req = self.make_request(config=config2, environ={ "HTTP_HOST": "host1.com", }) id = tokenlib.make_token({"uid": 42}, secret="secret11") key = tokenlib.get_token_secret(id, secret="secret11") macauthlib.sign_request(req, id, key) self.assertEquals(authenticated_userid(req), 42) # It should accept a request signed with the new secret on host1. req = self.make_request(config=config2, environ={ "HTTP_HOST": "host1.com", }) id = tokenlib.make_token({"uid": 42}, secret="secret12") key = tokenlib.get_token_secret(id, secret="secret12") macauthlib.sign_request(req, id, key) self.assertEquals(authenticated_userid(req), 42) # It should reject a request signed with secret from other host. req = self.make_request(config=config2, environ={ "HTTP_HOST": "host2.com", }) id = tokenlib.make_token({"uid": 42}, secret="secret12") key = tokenlib.get_token_secret(id, secret="secret12") macauthlib.sign_request(req, id, key) self.assertRaises(HTTPUnauthorized, authenticated_userid, req) # It should reject a request over plain http when host2 is ssl. req = self.make_request(config=config2, environ={ "HTTP_HOST": "host2.com", }) id = tokenlib.make_token({"uid": 42}, secret="secret22") key = tokenlib.get_token_secret(id, secret="secret22") macauthlib.sign_request(req, id, key) self.assertRaises(HTTPUnauthorized, authenticated_userid, req) # It should accept a request signed with the new secret on host2. req = self.make_request(config=config2, environ={ "HTTP_HOST": "host2.com", "wsgi.url_scheme": "https", }) id = tokenlib.make_token({"uid": 42}, secret="secret22") key = tokenlib.get_token_secret(id, secret="secret22") macauthlib.sign_request(req, id, key) self.assertEquals(authenticated_userid(req), 42) # It should accept a request to host1 with an explicit port number. # Use some trickery to give host_url a value with default port. req = ExpandoRequest(self.make_request(config=config2, environ={ "HTTP_HOST": "host1.com:80", "wsgi.url_scheme": "http", })) req.host_url = "http://host1.com:80" id = tokenlib.make_token({"uid": 42}, secret="secret11") key = tokenlib.get_token_secret(id, secret="secret11") macauthlib.sign_request(req, id, key) self.assertEquals(authenticated_userid(req), 42) # It should accept a request to host2 with an explicit port number. # Use some trickery to give host_url a value with default port. req = ExpandoRequest(self.make_request(config=config2, environ={ "HTTP_HOST": "host2.com:443", "wsgi.url_scheme": "https", })) req.host_url = "https://host2.com:443" id = tokenlib.make_token({"uid": 42}, secret="secret22") key = tokenlib.get_token_secret(id, secret="secret22") macauthlib.sign_request(req, id, key) self.assertEquals(authenticated_userid(req), 42) # It should accept a request to host3 on a custom port. req = self.make_request(config=config2, environ={ "HTTP_HOST": "host3.com:444", "wsgi.url_scheme": "https", }) id = tokenlib.make_token({"uid": 42}, secret="secret32") key = tokenlib.get_token_secret(id, secret="secret32") macauthlib.sign_request(req, id, key) self.assertEquals(authenticated_userid(req), 42) # It should reject unknown hostnames. req = self.make_request(config=config2, environ={ "HTTP_HOST": "host4.com", }) id = tokenlib.make_token({"uid": 42}, secret="secret12") key = tokenlib.get_token_secret(id, secret="secret12") macauthlib.sign_request(req, id, key) self.assertRaises(HTTPUnauthorized, authenticated_userid, req)
def generate(self): """Pick an identity, log in and generate the auth token.""" # If the server_url has a hash fragment, it's a storage node and # that's the secret. Otherwise it's a token server url. uid = random.randint(1, 1000000) url = urlparse(self.server_url) if url.fragment: endpoint = url._replace(fragment="", path="/1.5/" + str(uid)) self.endpoint_url = urlunparse(endpoint) data = { "uid": uid, "node": urlunparse(url._replace(fragment="")), "expires": time.time() + ASSERTION_LIFETIME, } self.auth_token = make_token(data, secret=url.fragment) self.auth_secret = derive(self.auth_token, secret=url.fragment) else: email = "user%s@%s" % (uid, MOCKMYID_DOMAIN) exp = time.time() + ASSERTION_LIFETIME + self.timeskew assertion = browserid.tests.support.make_assertion( email=email, audience=self.server_url, issuer=MOCKMYID_DOMAIN, issuer_keypair=(None, MOCKMYID_PRIVATE_KEY), exp=int(exp * 1000), ) token_url = self.server_url + "/1.0/sync/1.5" response = json_request(token_url, headers={ "Authorization": "BrowserID " + assertion, }) # Maybe timeskew between client and server? if response['status'] == 401: server_time = int(response['headers']["X-Timestamp"]) self.timeskew = server_time - int(time.time()) exp = time.time() + ASSERTION_LIFETIME + self.timeskew assertion = browserid.tests.support.make_assertion( email=email, audience=self.server_url, issuer=MOCKMYID_DOMAIN, issuer_keypair=(None, MOCKMYID_PRIVATE_KEY), exp=int(exp * 1000), ) response = json_request(token_url, headers={ "Authorization": "BrowserID " + assertion, }) if response['status'] > 299: raise ValueError(response['status']) credentials = response['content'] self.auth_token = credentials["id"].encode('ascii') self.auth_secret = credentials["key"].encode('ascii') self.endpoint_url = credentials["api_endpoint"] url = urlparse(self.endpoint_url) self.endpoint_scheme = url.scheme self.endpoint_path = url.path if ':' in url.netloc: self.endpoint_host, self.endpoint_port = url.netloc.rsplit(":", 1) else: self.endpoint_host = url.netloc if url.scheme == "http": self.endpoint_port = "80" else: self.endpoint_port = "443"
def return_token(request): """This service does the following process: - validates the Browser-ID assertion provided on the Authorization header - allocates when necessary a node to the user for the required service - deals with the X-Conditions-Accepted header - returns a JSON mapping containing the following values: - **id** -- a signed authorization token, containing the user's id for hthe application and the node. - **secret** -- a secret derived from the shared secret - **uid** -- the user id for this servic - **api_endpoint** -- the root URL for the user for the service. """ # at this stage, we are sure that the assertion, application and version # number were valid, so let's build the authentication token and return it. backend = request.registry.getUtility(INodeAssignment) email = request.validated['assertion']['email'] application = request.validated['application'] version = request.validated['version'] pattern = request.validated['pattern'] service = get_service_name(application, version) accepted = request.validated['x-conditions-accepted'] # get the node or allocate one if none is already set uid, node, to_accept = backend.get_node(email, service) if to_accept is not None: # the backend sent a tos url, meaning the user needs to # sign it, we want to compare both tos and raise a 403 # if they are not equal if not accepted: to_accept = dict([(name, value) for name, value, __ in to_accept]) raise json_error(403, location='header', description='Need to accept conditions', name='X-Conditions-Accepted', condition_urls=to_accept) # at this point, either the tos were signed or the service does not # have any ToS if node is None or uid is None: metlog = request.registry['metlog'] start = time.time() try: uid, node = backend.allocate_node(email, service) finally: duration = time.time() - start metlog.timer_send("token.sql.allocate_node", duration) secrets = request.registry.settings['tokenserver.secrets_file'] node_secrets = secrets.get(node) if not node_secrets: raise Exception("The specified node does not have any shared secret") secret = node_secrets[-1] # the last one is the most recent one token_duration = request.registry.settings.get( 'tokenserver.token_duration', DEFAULT_TOKEN_DURATION) token = make_token({'uid': uid, 'service_entry': node}, timeout=token_duration, secret=secret) # XXX needs to be renamed as 'get_derived_secret' because # it's not clear here it's a derived secret = get_token_secret(token, secret=secret) api_endpoint = pattern.format(uid=uid, service=service, node=node) # FIXME add the algo used to generate the token return {'id': token, 'key': secret, 'uid': uid, 'api_endpoint': api_endpoint, 'duration': token_duration}
def return_token(request): """This service does the following process: - validates the BrowserID assertion provided on the Authorization header - allocates when necessary a node to the user for the required service - checks generation numbers and x-client-state header - returns a JSON mapping containing the following values: - **id** -- a signed authorization token, containing the user's id for hthe application and the node. - **secret** -- a secret derived from the shared secret - **uid** -- the user id for this servic - **api_endpoint** -- the root URL for the user for the service. """ # at this stage, we are sure that the assertion, application and version # number were valid, so let's build the authentication token and return it. backend = request.registry.getUtility(INodeAssignment) settings = request.registry.settings email = request.validated['assertion']['email'] try: idp_claims = request.validated['assertion']['idpClaims'] generation = idp_claims['fxa-generation'] if not isinstance(generation, (int, long)): raise _unauthorized("invalid-generation") except KeyError: generation = 0 application = request.validated['application'] version = request.validated['version'] pattern = request.validated['pattern'] service = get_service_name(application, version) client_state = request.validated['client-state'] with metrics_timer('tokenserver.backend.get_user', request): user = backend.get_user(service, email) if not user: allowed = settings.get('tokenserver.allow_new_users', True) if not allowed: raise _unauthorized('invalid-credentials') with metrics_timer('tokenserver.backend.allocate_user', request): user = backend.allocate_user(service, email, generation, client_state) # Update if this client is ahead of previously-seen clients. updates = {} if generation > user['generation']: updates['generation'] = generation if client_state != user['client_state']: # Don't revert from some-client-state to no-client-state. if not client_state: raise _unauthorized('invalid-client-state') # Don't revert to a previous client-state. if client_state in user['old_client_states']: raise _unauthorized('invalid-client-state') # If the IdP has been sending generation numbers, then # don't update client-state without a change in generation number. if user['generation'] > 0 and 'generation' not in updates: raise _unauthorized('invalid-client-state') updates['client_state'] = client_state if updates: with metrics_timer('tokenserver.backend.update_user', request): backend.update_user(service, user, **updates) # Error out if this client is behind some previously-seen client. # This is done after the updates because some other, even more up-to-date # client may have raced with a concurrent update. if user['generation'] > generation: raise _unauthorized("invalid-generation") secrets = settings['tokenserver.secrets'] node_secrets = secrets.get(user['node']) if not node_secrets: raise Exception("The specified node does not have any shared secret") secret = node_secrets[-1] # the last one is the most recent one token_duration = settings.get( 'tokenserver.token_duration', DEFAULT_TOKEN_DURATION ) try: requested_duration = int(request.params["duration"]) except (KeyError, ValueError): pass else: if 0 < requested_duration < token_duration: token_duration = requested_duration token_data = { 'uid': user['uid'], 'node': user['node'], 'expires': int(time.time()) + token_duration, } token = tokenlib.make_token(token_data, secret=secret) secret = tokenlib.get_derived_secret(token, secret=secret) endpoint = pattern.format( uid=user['uid'], service=service, node=user['node'] ) return {'id': token, 'key': secret, 'uid': user['uid'], 'api_endpoint': endpoint, 'duration': token_duration, 'hashalg': tokenlib.DEFAULT_HASHMOD}
def test_that_macauth_can_use_per_node_hostname_secrets(self): with tempfile.NamedTemporaryFile() as sf: # Write some secrets to a file. sf.write("http://host1.com,0001:secret11,0002:secret12\n") sf.write("https://host2.com,0001:secret21,0002:secret22\n") sf.write("https://host3.com:444,0001:secret31,0002:secret32\n") sf.flush() # Configure the plugin to load them. config2 = pyramid.testing.setUp() config2.add_settings(DEFAULT_SETTINGS) config2.add_settings({ "macauth.secrets_file": sf.name, }) config2.include("mozsvc.user") config2.commit() # It should accept a request signed with the old secret on host1. req = self.make_request(config=config2, environ={ "HTTP_HOST": "host1.com", }) id = tokenlib.make_token({"uid": 42}, secret="secret11") key = tokenlib.get_token_secret(id, secret="secret11") macauthlib.sign_request(req, id, key) self.assertEquals(authenticated_userid(req), 42) # It should accept a request signed with the new secret on host1. req = self.make_request(config=config2, environ={ "HTTP_HOST": "host1.com", }) id = tokenlib.make_token({"uid": 42}, secret="secret12") key = tokenlib.get_token_secret(id, secret="secret12") macauthlib.sign_request(req, id, key) self.assertEquals(authenticated_userid(req), 42) # It should reject a request signed with secret from other host. req = self.make_request(config=config2, environ={ "HTTP_HOST": "host2.com", }) id = tokenlib.make_token({"uid": 42}, secret="secret12") key = tokenlib.get_token_secret(id, secret="secret12") macauthlib.sign_request(req, id, key) self.assertRaises(HTTPUnauthorized, authenticated_userid, req) # It should reject a request over plain http when host2 is ssl. req = self.make_request(config=config2, environ={ "HTTP_HOST": "host2.com", }) id = tokenlib.make_token({"uid": 42}, secret="secret22") key = tokenlib.get_token_secret(id, secret="secret22") macauthlib.sign_request(req, id, key) self.assertRaises(HTTPUnauthorized, authenticated_userid, req) # It should accept a request signed with the new secret on host2. req = self.make_request(config=config2, environ={ "HTTP_HOST": "host2.com", "wsgi.url_scheme": "https", }) id = tokenlib.make_token({"uid": 42}, secret="secret22") key = tokenlib.get_token_secret(id, secret="secret22") macauthlib.sign_request(req, id, key) self.assertEquals(authenticated_userid(req), 42) # It should accept a request to host1 with an explicit port number. # Use some trickery to give host_url a value with default port. req = ExpandoRequest( self.make_request(config=config2, environ={ "HTTP_HOST": "host1.com:80", "wsgi.url_scheme": "http", })) req.host_url = "http://host1.com:80" id = tokenlib.make_token({"uid": 42}, secret="secret11") key = tokenlib.get_token_secret(id, secret="secret11") macauthlib.sign_request(req, id, key) self.assertEquals(authenticated_userid(req), 42) # It should accept a request to host2 with an explicit port number. # Use some trickery to give host_url a value with default port. req = ExpandoRequest( self.make_request(config=config2, environ={ "HTTP_HOST": "host2.com:443", "wsgi.url_scheme": "https", })) req.host_url = "https://host2.com:443" id = tokenlib.make_token({"uid": 42}, secret="secret22") key = tokenlib.get_token_secret(id, secret="secret22") macauthlib.sign_request(req, id, key) self.assertEquals(authenticated_userid(req), 42) # It should accept a request to host3 on a custom port. req = self.make_request(config=config2, environ={ "HTTP_HOST": "host3.com:444", "wsgi.url_scheme": "https", }) id = tokenlib.make_token({"uid": 42}, secret="secret32") key = tokenlib.get_token_secret(id, secret="secret32") macauthlib.sign_request(req, id, key) self.assertEquals(authenticated_userid(req), 42) # It should reject unknown hostnames. req = self.make_request(config=config2, environ={ "HTTP_HOST": "host4.com", }) id = tokenlib.make_token({"uid": 42}, secret="secret12") key = tokenlib.get_token_secret(id, secret="secret12") macauthlib.sign_request(req, id, key) self.assertRaises(HTTPUnauthorized, authenticated_userid, req)