def test_GET_list_allocated_returns_only_allocated_with_user_token(self): # If the user's allocated nodes have different session tokens, # list_allocated should only return the nodes that have the # current request's token on them. node_1 = factory.make_node( status=NODE_STATUS.ALLOCATED, owner=self.logged_in_user, token=get_auth_tokens(self.logged_in_user)[0]) second_token = create_auth_token(self.logged_in_user) factory.make_node( owner=self.logged_in_user, status=NODE_STATUS.ALLOCATED, token=second_token) user_2 = factory.make_user() create_auth_token(user_2) factory.make_node( owner=self.logged_in_user, status=NODE_STATUS.ALLOCATED, token=second_token) # At this point we have two nodes owned by the same user but # allocated with different tokens, and a third node allocated to # someone else entirely. We expect list_allocated to # return the node with the same token as the one used in # self.client, which is the one we set on node_1 above. response = self.client.get(reverse('nodes_handler'), { 'op': 'list_allocated'}) self.assertEqual(httplib.OK, response.status_code) parsed_result = json.loads(response.content) self.assertItemsEqual( [node_1.system_id], extract_system_ids(parsed_result))
def test_GET_list_allocated_returns_only_allocated_with_user_token(self): # If the user's allocated nodes have different session tokens, # list_allocated should only return the nodes that have the # current request's token on them. node_1 = factory.make_node(status=NODE_STATUS.ALLOCATED, owner=self.logged_in_user, token=get_auth_tokens( self.logged_in_user)[0]) second_token = create_auth_token(self.logged_in_user) factory.make_node(owner=self.logged_in_user, status=NODE_STATUS.ALLOCATED, token=second_token) user_2 = factory.make_user() create_auth_token(user_2) factory.make_node(owner=self.logged_in_user, status=NODE_STATUS.ALLOCATED, token=second_token) # At this point we have two nodes owned by the same user but # allocated with different tokens, and a third node allocated to # someone else entirely. We expect list_allocated to # return the node with the same token as the one used in # self.client, which is the one we set on node_1 above. response = self.client.get(reverse('nodes_handler'), {'op': 'list_allocated'}) self.assertEqual(httplib.OK, response.status_code) parsed_result = json.loads(response.content) self.assertItemsEqual([node_1.system_id], extract_system_ids(parsed_result))
def test_list(self): user = factory.make_User() handler = TokenHandler(user, {}, None) create_auth_token(user) expected_tokens = [ self.dehydrate_token(token) for token in get_auth_tokens(user) ] self.assertItemsEqual(expected_tokens, handler.list({}))
def test__returns_first_of_existing_credentials(self): username = factory.make_name("username") password = factory.make_name("password") user = factory.make_User(username, password) [token] = get_auth_tokens(user) for i in range(1, 6): create_auth_token(user, "Token #%d" % i) response = self.client.post(reverse("authenticate"), data={ "username": username, "password": password, }) self.assertThat(response, HasStatusCode(HTTPStatus.OK)) self.assertThat(json_load_bytes(response.content), Equals(token_to_dict(token)))
def test_acquire(self): node = factory.make_node(status=NODE_STATUS.READY) user = factory.make_user() token = create_auth_token(user) node.acquire(user, token) self.assertEqual(user, node.owner) self.assertEqual(NODE_STATUS.ALLOCATED, node.status)
def test_POST_update_nodes_allows_rack_controller(self): tag = factory.make_Tag() rack_controller = factory.make_RackController() node = factory.make_Node() client = make_worker_client(rack_controller) tokens = list(get_auth_tokens(rack_controller.owner)) if len(tokens) > 0: # Use the latest token. token = tokens[-1] else: token = create_auth_token(rack_controller.owner) token.save() creds = convert_tuple_to_string(get_creds_tuple(token)) response = client.post( self.get_tag_uri(tag), { 'op': 'update_nodes', 'add': [node.system_id], 'rack_controller': rack_controller.system_id, 'credentials': creds, }) self.assertEqual(http.client.OK, response.status_code) parsed_result = json.loads( response.content.decode(settings.DEFAULT_CHARSET)) self.assertEqual({'added': 1, 'removed': 0}, parsed_result) self.assertItemsEqual([node], tag.node_set.all())
def make_worker_client(rack_controller): """Create a test client logged in as if it were `rack_controller`.""" assert ( get_worker_user() == rack_controller.owner ), "Rack controller owner should be the MAAS worker user." token = create_auth_token(rack_controller.owner) return MAASSensibleOAuthClient(rack_controller.owner, token=token)
def test_create_auth_token(self): user = factory.make_user() token = create_auth_token(user) self.assertEqual(user, token.user) self.assertEqual(user, token.consumer.user) self.assertTrue(token.is_approved) self.assertConsumerValid(token.consumer) self.assertTokenValid(token)
def test_acquire(self): node = factory.make_node(status=NODE_STATUS.READY) user = factory.make_user() token = create_auth_token(user) agent_name = factory.make_name('agent-name') node.acquire(user, token, agent_name) self.assertEqual( (user, NODE_STATUS.ALLOCATED, agent_name), (node.owner, node.status, node.agent_name))
def save(self, *args, **kwargs): if self.api_token_id is None: # Avoid circular imports. from maasserver.models.user import create_auth_token from maasserver.worker_user import get_worker_user api_token = create_auth_token(get_worker_user()) self.api_token = api_token self.api_key = api_token.key return super(NodeGroup, self).save(*args, **kwargs)
def _create_token(self, node): """Create an OAuth token for a given node. :param node: The system that is to be allowed access to the metadata service. :type node: Node :return: Token for the node to use. :rtype: piston.models.Token """ token = create_auth_token(get_node_init_user()) self.create(node=node, token=token, key=token.key) return token
def authenticate(request): """Authenticate a user, but do *not* log them in. If the correct username and password are given, credentials suitable for use with MAAS's Web API are returned. This can be used by client libraries to exchange a username+password for an API token. Accepts HTTP POST requests with the following parameters: username: The user's username. password: The user's password. consumer: The name to use for the token, which can be used to later understand which consumer requested and is using a token. Optional. If `consumer` is provided, existing credentials belonging to the user with a matching consumer will be returned, if any exist, else new credentials will be created and labelled with `consumer` before being returned. If `consumer` is not provided, the earliest created credentials belonging to the user will be returned. If no preexisting credentials exist, new credentials will be created and returned. """ if request.method != "POST": return HttpResponseNotAllowed(["POST"]) username = request.POST.get("username") password = request.POST.get("password") consumer = request.POST.get("consumer") user = dj_authenticate(username=username, password=password) if user is None or not user.is_active: # This is_active check mimics confirm_login_allowed from Django's # django.contrib.auth.forms.AuthenticationForm. return HttpResponseForbidden() # Find an existing token. There might be more than one so take the first. tokens = get_auth_tokens(user) if consumer is not None: tokens = tokens.filter(consumer__name=consumer) token = tokens.first() # When no existing token is found, create a new one. if token is None: token = create_auth_token(user, consumer) # Return something with the same shape as that rendered by # AccountHandler.create_authorisation_token. return JsonResponse({ "consumer_key": token.consumer.key, "name": token.consumer.name, "token_key": token.key, "token_secret": token.secret, })
def test_update(self): user = factory.make_User() handler = TokenHandler(user, {}, None) name = factory.make_name("name") token = create_auth_token(user, name) new_name = factory.make_name("name") updated_token = handler.update({"id": token.id, "name": new_name}) self.assertThat(updated_token, KeysEqual("id", "key", "secret", "consumer")) self.assertEqual(new_name, updated_token["consumer"]["name"]) event = Event.objects.get(type__level=AUDIT) self.assertIsNotNone(event) self.assertEqual(event.description, "Modified consumer name of token.")
def create(self, params): """Create a Token.""" token = create_auth_token(self.user, params.get("name")) request = HttpRequest() request.user = self.user create_audit_event( EVENT_TYPES.AUTHORISATION, ENDPOINT.UI, request, None, "Created token.", ) return self.full_dehydrate(token)
def create_authorisation_token(self): """Create a new Token and its related Consumer (OAuth authorisation). :return: A tuple containing the Consumer and the Token that were created. :rtype: tuple """ # Avoid circular imports. from maasserver.models.user import create_auth_token token = create_auth_token(self.user) return token.consumer, token
def create_authorisation_token(self, consumer_name=None): """Create a new Token and its related Consumer (OAuth authorisation). :return: A tuple containing the Consumer and the Token that were created. :rtype: tuple """ # Avoid circular imports. from maasserver.models.user import create_auth_token token = create_auth_token(self.user, consumer_name) return token.consumer, token
def test__returns_first_of_existing_named_credentials(self): username = factory.make_name("username") password = factory.make_name("password") consumer = factory.make_name("consumer") user = factory.make_User(username, password) tokens = [create_auth_token(user, consumer) for _ in range(1, 6)] response = self.client.post(reverse("authenticate"), data={ "username": username, "password": password, "consumer": consumer, }) self.assertThat(response, HasStatusCode(HTTPStatus.OK)) self.assertThat(json_load_bytes(response.content), Equals(token_to_dict(tokens[0])))
def test_POST_update_nodes_refuses_non_rack_controller(self): tag = factory.make_Tag() rack_controller = factory.make_RackController() node = factory.make_Node() token = create_auth_token(rack_controller.owner) token.save() creds = convert_tuple_to_string(get_creds_tuple(token)) response = self.client.post( self.get_tag_uri(tag), { 'op': 'update_nodes', 'add': [node.system_id], 'rack_controller': rack_controller.system_id, 'credentials': creds, }) self.assertEqual(http.client.FORBIDDEN, response.status_code) self.assertItemsEqual([], tag.node_set.all())
def test_POST_update_nodes_refuses_no_token(self): tag = factory.make_Tag() rack_controller = factory.make_RackController() node = factory.make_Node() # create a token for a different user token = create_auth_token(factory.make_User()) token.save() creds = convert_tuple_to_string(get_creds_tuple(token)) response = self.client.post( self.get_tag_uri(tag), { "op": "update_nodes", "add": [node.system_id], "rack_controller": rack_controller.system_id, "credentials": creds, }, ) self.assertEqual(http.client.FORBIDDEN, response.status_code) self.assertItemsEqual([], tag.node_set.all())
def test_calls_are_made_to_all_clusters(self): rpc_fixture = self.prepare_live_rpc() rack_controllers = [factory.make_RackController() for _ in range(3)] protocols = [] rack_creds = [] for rack in rack_controllers: tokens = list(get_auth_tokens(rack.owner)) if len(tokens) > 0: # Use the latest token. token = tokens[-1] else: token = create_auth_token(rack.owner) creds = convert_tuple_to_string(get_creds_tuple(token)) rack_creds.append(creds) protocol = rpc_fixture.makeCluster(rack, EvaluateTag) protocol.EvaluateTag.side_effect = always_succeed_with({}) protocols.append(protocol) tag = factory.make_Tag(populate=False) [d] = populate_tags(tag) # `d` is a testing-only convenience. We must wait for it to fire, and # we must do that from the reactor thread. wait_for_populate = asynchronous(lambda: d) wait_for_populate().wait(10) for rack, protocol, creds in zip(rack_controllers, protocols, rack_creds): self.expectThat( protocol.EvaluateTag, MockCalledOnceWith( protocol, tag_name=tag.name, tag_definition=tag.definition, system_id=rack.system_id, tag_nsmap=ANY, credentials=creds, nodes=ANY, ), )
def test_get(self): user = factory.make_User() handler = TokenHandler(user, {}, None) token = create_auth_token(user) self.assertEqual(self.dehydrate_token(token), handler.get({"id": token.id}))
def test_add_node_with_token(self): user = factory.make_user() token = create_auth_token(user) node = factory.make_node(token=token) self.assertEqual(token, node.token)
def test_delete(self): user = factory.make_User() token = create_auth_token(user) handler = TokenHandler(user, {}, None) handler.delete({"id": token.id}) self.assertIsNone(get_one(get_auth_tokens(user).filter(id=token.id)))
def test_get_doesnt_work_if_not_owned(self): user = factory.make_User() handler = TokenHandler(user, {}, None) not_owned_token = create_auth_token(factory.make_User()) self.assertRaises(HandlerDoesNotExistError, handler.get, {"id": not_owned_token.id})
def _get_or_create_auth_token(user): """Get the most recent OAuth token for `user`, or create one.""" for token in reversed(get_auth_tokens(user)): return token else: return create_auth_token(user)
def test_get_auth_tokens_finds_tokens_for_user(self): user = factory.make_user() token = create_auth_token(user) self.assertIn(token, get_auth_tokens(user))
def create_token(self, params=None): if params is None: params = {} return create_auth_token(**params)
def test_get_creds_tuple_integrates_with_api_client(self): creds_tuple = get_creds_tuple(create_auth_token(factory.make_user())) self.assertEqual( creds_tuple, convert_string_to_tuple(convert_tuple_to_string(creds_tuple)))
def test_get_creds_tuple_returns_creds(self): token = create_auth_token(factory.make_user()) self.assertEqual( (token.consumer.key, token.key, token.secret), get_creds_tuple(token))
def test_get_creds_tuple_returns_creds(self): token = create_auth_token(factory.make_user()) self.assertEqual((token.consumer.key, token.key, token.secret), get_creds_tuple(token))
def test_get_auth_tokens_ignores_unapproved_tokens(self): user = factory.make_user() token = create_auth_token(user) token.is_approved = False token.save() self.assertNotIn(token, get_auth_tokens(user))
def test_get_auth_tokens_ignores_other_users(self): user, other_user = factory.make_user(), factory.make_user() unrelated_token = create_auth_token(other_user) self.assertNotIn(unrelated_token, get_auth_tokens(user))