Exemple #1
0
 def test_invalid_oauth_request(self):
     # An OAuth-signed request that does not validate is an error.
     user = factory.make_user()
     client = OAuthAuthenticatedClient(user)
     get_auth_tokens(user).delete()  # Delete the user's API keys.
     response = client.post(reverse('nodes_handler'), {'op': 'start'})
     observed = response.status_code, response.content
     expected = (
         Equals(httplib.UNAUTHORIZED),
         Contains("Invalid access token:"),
         )
     self.assertThat(observed, MatchesListwise(expected))
Exemple #2
0
 def test_invalid_oauth_request(self):
     # An OAuth-signed request that does not validate is an error.
     user = factory.make_user()
     client = OAuthAuthenticatedClient(user)
     get_auth_tokens(user).delete()  # Delete the user's API keys.
     response = client.post(reverse('nodes_handler'), {'op': 'start'})
     observed = response.status_code, response.content
     expected = (
         Equals(httplib.UNAUTHORIZED),
         Contains("Invalid access token:"),
     )
     self.assertThat(observed, MatchesListwise(expected))
Exemple #3
0
 def test_invalid_oauth_request(self):
     # An OAuth-signed request that does not validate is an error.
     user = factory.make_User()
     client = MAASSensibleOAuthClient(user)
     # Delete the user's API keys.
     get_auth_tokens(user).delete()
     response = client.post(reverse("nodes_handler"), {"op": "start"})
     observed = response.status_code, response.content
     expected = (
         Equals(http.client.UNAUTHORIZED),
         Contains(b"Invalid access token:"),
     )
     self.assertThat(observed, MatchesListwise(expected))
Exemple #4
0
 def test__returns_new_credentials(self):
     username = factory.make_name("username")
     password = factory.make_name("password")
     user = factory.make_User(username, password)
     get_auth_tokens(user).delete()  # Delete all tokens.
     response = self.client.post(reverse("authenticate"),
                                 data={
                                     "username": username,
                                     "password": password,
                                 })
     self.assertThat(response, HasStatusCode(HTTPStatus.OK))
     [token] = get_auth_tokens(user)
     self.assertThat(json_load_bytes(response.content),
                     Equals(token_to_dict(token)))
Exemple #5
0
 def test__returns_new_named_credentials(self):
     username = factory.make_name("username")
     password = factory.make_name("password")
     consumer = factory.make_name("consumer")
     user = factory.make_User(username, password)
     get_auth_tokens(user).delete()  # Delete all tokens.
     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),
                     ContainsDict({"name": Equals(consumer)}))
Exemple #6
0
 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())
Exemple #7
0
    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))
Exemple #8
0
    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))
Exemple #9
0
 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({}))
Exemple #10
0
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,
    })
Exemple #11
0
def give_api_credentials_to_user(user_from, user_dest):
    """Gives one user's API credentials to another.

    This ensures that users of the shared namespace environment continue to
    operate within the legacy shared namespace environment by default via the
    API (e.g. from the command-line client, or from Juju).
    """
    for token in get_auth_tokens(user_from):
        consumer = token.consumer
        consumer.user = user_dest
        consumer.save()
        token.user = user_dest
        token.save()
Exemple #12
0
    def get_authorisation_tokens(self):
        """Fetches all the user's OAuth tokens.

        :return: A QuerySet of the tokens.
        :rtype: django.db.models.query.QuerySet_

        .. _django.db.models.query.QuerySet: https://docs.djangoproject.com/
           en/dev/ref/models/querysets/

        """
        # Avoid circular imports.
        from maasserver.models.user import get_auth_tokens

        return get_auth_tokens(self.user)
Exemple #13
0
    def get_authorisation_tokens(self):
        """Fetches all the user's OAuth tokens.

        :return: A QuerySet of the tokens.
        :rtype: django.db.models.query.QuerySet_

        .. _django.db.models.query.QuerySet: https://docs.djangoproject.com/
           en/dev/ref/models/querysets/

        """
        # Avoid circular imports.
        from maasserver.models.user import get_auth_tokens

        return get_auth_tokens(self.user)
Exemple #14
0
 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)))
Exemple #15
0
 def login(self, *, user=None, token=None):
     """Override Django's `Client.login`."""
     if user is None:
         assert token is not None
         return self._token_set(token)
     else:
         if user.is_anonymous:
             self._token_clear()
             return False
         elif token is None:
             token = get_auth_tokens(user)[0]
             return self._token_set(token)
         else:
             assert token.user == user
             return self._token_set(token)
Exemple #16
0
    def __init__(self, user, token=None):
        """Initialize an oauth-authenticated test client.

        :param user: The user to authenticate.
        :type user: django.contrib.auth.models.User
        :param token: Optional token to authenticate `user` with.  If
            no `token` is given, the user's first token will be used.
        :type token: oauth.oauth.OAuthToken
        """
        super(OAuthAuthenticatedClient, self).__init__()
        if token is None:
            # Get the user's first token.
            token = get_auth_tokens(user)[0]
        assert token.user == user, "Token does not match User."
        consumer = token.consumer
        self.consumer = OAuthConsumer(str(consumer.key), str(consumer.secret))
        self.token = OAuthToken(str(token.key), str(token.secret))
Exemple #17
0
def check_rack_controller_access(request, rack_controller):
    """Validate API access by worker for `rack_controller`.

    This supports a rack controller accessing the update_nodes API.  If the
    request is done by anyone but the rack controller for this
    particular rack controller, the function raises :class:`PermissionDenied`.
    """
    try:
        key = extract_oauth_key(request)
    except Unauthorized as e:
        raise PermissionDenied(str(e))

    tokens = list(get_auth_tokens(rack_controller.owner))
    # Use the latest token if available
    token = tokens[-1] if tokens else None
    if token is None or key != token.key:
        raise PermissionDenied("Only allowed for the %r rack controller." %
                               (rack_controller.hostname))
Exemple #18
0
    def test_GET_list_allocated_filters_by_id(self):
        # list_allocated takes an optional list of 'id' parameters to
        # filter returned results.
        current_token = get_auth_tokens(self.logged_in_user)[0]
        nodes = []
        for i in range(3):
            nodes.append(factory.make_node(
                status=NODE_STATUS.ALLOCATED,
                owner=self.logged_in_user, token=current_token))

        required_node_ids = [nodes[0].system_id, nodes[1].system_id]
        response = self.client.get(reverse('nodes_handler'), {
            'op': 'list_allocated',
            'id': required_node_ids,
        })
        self.assertEqual(httplib.OK, response.status_code)
        parsed_result = json.loads(response.content)
        self.assertItemsEqual(
            required_node_ids, extract_system_ids(parsed_result))
Exemple #19
0
    def __init__(self, user, token=None):
        """Initialize an oauth-authenticated test client.

        :param user: The user to authenticate.
        :type user: django.contrib.auth.models.User
        :param token: Optional token to authenticate `user` with.  If
            no `token` is given, the user's first token will be used.
        :type token: oauth.oauth.OAuthToken
        """
        super(OAuthAuthenticatedClient, self).__init__()
        if token is None:
            # Get the user's first token.
            token = get_auth_tokens(user)[0]
        assert token.user == user, "Token does not match User."
        consumer = token.consumer
        self.consumer = OAuthConsumer(consumer.key.encode("ascii"),
                                      consumer.secret.encode("ascii"))
        self.token = OAuthToken(token.key.encode("ascii"),
                                token.secret.encode("ascii"))
Exemple #20
0
    def test_GET_list_allocated_filters_by_id(self):
        # list_allocated takes an optional list of 'id' parameters to
        # filter returned results.
        current_token = get_auth_tokens(self.logged_in_user)[0]
        nodes = []
        for i in range(3):
            nodes.append(
                factory.make_node(status=NODE_STATUS.ALLOCATED,
                                  owner=self.logged_in_user,
                                  token=current_token))

        required_node_ids = [nodes[0].system_id, nodes[1].system_id]
        response = self.client.get(reverse('nodes_handler'), {
            'op': 'list_allocated',
            'id': required_node_ids,
        })
        self.assertEqual(httplib.OK, response.status_code)
        parsed_result = json.loads(response.content)
        self.assertItemsEqual(required_node_ids,
                              extract_system_ids(parsed_result))
Exemple #21
0
    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,
                ),
            )
Exemple #22
0
 def get_queryset(self, for_list=False):
     """Return `QuerySet` for `Token` owned by `user`."""
     return get_auth_tokens(self.user)
Exemple #23
0
 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))
Exemple #24
0
 def test_token_creation(self):
     # A token is created each time a user is created.
     user = factory.make_User()
     [token] = get_auth_tokens(user)
     self.assertEqual(user, token.user)
Exemple #25
0
 def test_token_creation(self):
     # A token is created each time a user is created.
     user = factory.make_user()
     [token] = get_auth_tokens(user)
     self.assertEqual(user, token.user)
Exemple #26
0
 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))
Exemple #27
0
 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)))
Exemple #28
0
 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))
Exemple #29
0
 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))
Exemple #30
0
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)
Exemple #31
0
 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))
Exemple #32
0
 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))