github.com/bugraaydogar/snapd@v0.0.0-20210315170335-8c70bb858939/daemon/api_asserts_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016-2019 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package daemon_test
    21  
    22  import (
    23  	"bytes"
    24  	"encoding/json"
    25  	"io"
    26  	"net/http"
    27  	"net/http/httptest"
    28  	"sort"
    29  	"strconv"
    30  
    31  	"gopkg.in/check.v1"
    32  
    33  	"github.com/snapcore/snapd/asserts"
    34  	"github.com/snapcore/snapd/asserts/assertstest"
    35  	"github.com/snapcore/snapd/asserts/sysdb"
    36  	"github.com/snapcore/snapd/daemon"
    37  	"github.com/snapcore/snapd/dirs"
    38  	"github.com/snapcore/snapd/overlord"
    39  	"github.com/snapcore/snapd/overlord/assertstate"
    40  	"github.com/snapcore/snapd/overlord/assertstate/assertstatetest"
    41  	"github.com/snapcore/snapd/overlord/auth"
    42  	"github.com/snapcore/snapd/overlord/snapstate"
    43  	"github.com/snapcore/snapd/store/storetest"
    44  	"github.com/snapcore/snapd/testutil"
    45  )
    46  
    47  type assertsSuite struct {
    48  	d *daemon.Daemon
    49  	o *overlord.Overlord
    50  
    51  	storeSigning    *assertstest.StoreStack
    52  	trustedRestorer func()
    53  
    54  	storetest.Store
    55  	mockAssertionFn func(at *asserts.AssertionType, headers []string, user *auth.UserState) (asserts.Assertion, error)
    56  }
    57  
    58  var _ = check.Suite(&assertsSuite{})
    59  
    60  func (s *assertsSuite) SetUpTest(c *check.C) {
    61  	dirs.SetRootDir(c.MkDir())
    62  
    63  	s.o = overlord.Mock()
    64  	s.d = daemon.NewWithOverlord(s.o)
    65  
    66  	// adds an assertion db
    67  	s.storeSigning = assertstest.NewStoreStack("can0nical", nil)
    68  	s.trustedRestorer = sysdb.InjectTrusted(s.storeSigning.Trusted)
    69  
    70  	st := s.o.State()
    71  	st.Lock()
    72  	snapstate.ReplaceStore(st, s)
    73  	st.Unlock()
    74  	assertstate.Manager(st, s.o.TaskRunner())
    75  }
    76  
    77  func (s *assertsSuite) TearDownTest(c *check.C) {
    78  	s.trustedRestorer()
    79  	s.o = nil
    80  	s.d = nil
    81  	s.mockAssertionFn = nil
    82  }
    83  
    84  func (s *assertsSuite) TestGetAsserts(c *check.C) {
    85  	resp := daemon.GetAssertTypeNames(daemon.AssertsCmd, nil, nil)
    86  	c.Check(resp.Status, check.Equals, 200)
    87  	c.Check(resp.Type, check.Equals, daemon.ResponseTypeSync)
    88  	c.Check(resp.Result, check.DeepEquals, map[string][]string{"types": asserts.TypeNames()})
    89  }
    90  
    91  func (s *assertsSuite) addAsserts(assertions ...asserts.Assertion) {
    92  	st := s.o.State()
    93  	st.Lock()
    94  	defer st.Unlock()
    95  	assertstatetest.AddMany(st, s.storeSigning.StoreAccountKey(""))
    96  	assertstatetest.AddMany(st, assertions...)
    97  }
    98  
    99  func (s *assertsSuite) TestAssertOK(c *check.C) {
   100  	// add store key
   101  	s.addAsserts()
   102  
   103  	st := s.o.State()
   104  
   105  	acct := assertstest.NewAccount(s.storeSigning, "developer1", nil, "")
   106  	buf := bytes.NewBuffer(asserts.Encode(acct))
   107  	// Execute
   108  	req, err := http.NewRequest("POST", "/v2/assertions", buf)
   109  	c.Assert(err, check.IsNil)
   110  	rsp := daemon.DoAssert(daemon.AssertsCmd, req, nil)
   111  	// Verify (external)
   112  	c.Check(rsp.Type, check.Equals, daemon.ResponseTypeSync)
   113  	c.Check(rsp.Status, check.Equals, 200)
   114  	// Verify (internal)
   115  	st.Lock()
   116  	defer st.Unlock()
   117  	_, err = assertstate.DB(st).Find(asserts.AccountType, map[string]string{
   118  		"account-id": acct.AccountID(),
   119  	})
   120  	c.Check(err, check.IsNil)
   121  }
   122  
   123  func (s *assertsSuite) TestAssertStreamOK(c *check.C) {
   124  	st := s.o.State()
   125  
   126  	acct := assertstest.NewAccount(s.storeSigning, "developer1", nil, "")
   127  	buf := &bytes.Buffer{}
   128  	enc := asserts.NewEncoder(buf)
   129  	err := enc.Encode(acct)
   130  	c.Assert(err, check.IsNil)
   131  	err = enc.Encode(s.storeSigning.StoreAccountKey(""))
   132  	c.Assert(err, check.IsNil)
   133  
   134  	// Execute
   135  	req, err := http.NewRequest("POST", "/v2/assertions", buf)
   136  	c.Assert(err, check.IsNil)
   137  	rsp := daemon.DoAssert(daemon.AssertsCmd, req, nil)
   138  	// Verify (external)
   139  	c.Check(rsp.Type, check.Equals, daemon.ResponseTypeSync)
   140  	c.Check(rsp.Status, check.Equals, 200)
   141  	// Verify (internal)
   142  	st.Lock()
   143  	defer st.Unlock()
   144  	_, err = assertstate.DB(st).Find(asserts.AccountType, map[string]string{
   145  		"account-id": acct.AccountID(),
   146  	})
   147  	c.Check(err, check.IsNil)
   148  }
   149  
   150  func (s *assertsSuite) TestAssertInvalid(c *check.C) {
   151  	// Setup
   152  	buf := bytes.NewBufferString("blargh")
   153  	req, err := http.NewRequest("POST", "/v2/assertions", buf)
   154  	c.Assert(err, check.IsNil)
   155  	rec := httptest.NewRecorder()
   156  	// Execute
   157  	daemon.AssertsCmd.POST(daemon.AssertsCmd, req, nil).ServeHTTP(rec, req)
   158  	// Verify (external)
   159  	c.Check(rec.Code, check.Equals, 400)
   160  	c.Check(rec.Body.String(), testutil.Contains,
   161  		"cannot decode request body into assertions")
   162  }
   163  
   164  func (s *assertsSuite) TestAssertError(c *check.C) {
   165  	// Setup
   166  	acct := assertstest.NewAccount(s.storeSigning, "developer1", nil, "")
   167  	buf := bytes.NewBuffer(asserts.Encode(acct))
   168  	req, err := http.NewRequest("POST", "/v2/assertions", buf)
   169  	c.Assert(err, check.IsNil)
   170  	rec := httptest.NewRecorder()
   171  	// Execute
   172  	daemon.AssertsCmd.POST(daemon.AssertsCmd, req, nil).ServeHTTP(rec, req)
   173  	// Verify (external)
   174  	c.Check(rec.Code, check.Equals, 400)
   175  	c.Check(rec.Body.String(), testutil.Contains, "assert failed")
   176  }
   177  
   178  func (s *assertsSuite) TestAssertsFindManyAll(c *check.C) {
   179  	acct := assertstest.NewAccount(s.storeSigning, "developer1", map[string]interface{}{
   180  		"account-id": "developer1-id",
   181  	}, "")
   182  	s.addAsserts(acct)
   183  
   184  	// Execute
   185  	req, err := http.NewRequest("POST", "/v2/assertions/account", nil)
   186  	c.Assert(err, check.IsNil)
   187  	defer daemon.MockMuxVars(func(*http.Request) map[string]string {
   188  		return map[string]string{"assertType": "account"}
   189  	})()
   190  
   191  	rec := httptest.NewRecorder()
   192  	daemon.AssertsFindManyCmd.GET(daemon.AssertsFindManyCmd, req, nil).ServeHTTP(rec, req)
   193  	// Verify
   194  	c.Check(rec.Code, check.Equals, 200, check.Commentf("body %q", rec.Body))
   195  	c.Check(rec.HeaderMap.Get("Content-Type"), check.Equals, "application/x.ubuntu.assertion; bundle=y")
   196  	c.Check(rec.HeaderMap.Get("X-Ubuntu-Assertions-Count"), check.Equals, "4")
   197  	dec := asserts.NewDecoder(rec.Body)
   198  	a1, err := dec.Decode()
   199  	c.Assert(err, check.IsNil)
   200  	c.Check(a1.Type(), check.Equals, asserts.AccountType)
   201  
   202  	a2, err := dec.Decode()
   203  	c.Assert(err, check.IsNil)
   204  
   205  	a3, err := dec.Decode()
   206  	c.Assert(err, check.IsNil)
   207  
   208  	a4, err := dec.Decode()
   209  	c.Assert(err, check.IsNil)
   210  
   211  	_, err = dec.Decode()
   212  	c.Assert(err, check.Equals, io.EOF)
   213  
   214  	ids := []string{a1.(*asserts.Account).AccountID(), a2.(*asserts.Account).AccountID(), a3.(*asserts.Account).AccountID(), a4.(*asserts.Account).AccountID()}
   215  	sort.Strings(ids)
   216  	c.Check(ids, check.DeepEquals, []string{"can0nical", "canonical", "developer1-id", "generic"})
   217  }
   218  
   219  func (s *assertsSuite) TestAssertsFindManyFilter(c *check.C) {
   220  	acct := assertstest.NewAccount(s.storeSigning, "developer1", nil, "")
   221  	s.addAsserts(acct)
   222  
   223  	// Execute
   224  	req, err := http.NewRequest("POST", "/v2/assertions/account?username=developer1", nil)
   225  	c.Assert(err, check.IsNil)
   226  	defer daemon.MockMuxVars(func(*http.Request) map[string]string {
   227  		return map[string]string{"assertType": "account"}
   228  	})()
   229  
   230  	rec := httptest.NewRecorder()
   231  	daemon.AssertsFindManyCmd.GET(daemon.AssertsFindManyCmd, req, nil).ServeHTTP(rec, req)
   232  	// Verify
   233  	c.Check(rec.Code, check.Equals, 200, check.Commentf("body %q", rec.Body))
   234  	c.Check(rec.HeaderMap.Get("X-Ubuntu-Assertions-Count"), check.Equals, "1")
   235  	dec := asserts.NewDecoder(rec.Body)
   236  	a1, err := dec.Decode()
   237  	c.Assert(err, check.IsNil)
   238  	c.Check(a1.Type(), check.Equals, asserts.AccountType)
   239  	c.Check(a1.(*asserts.Account).Username(), check.Equals, "developer1")
   240  	c.Check(a1.(*asserts.Account).AccountID(), check.Equals, acct.AccountID())
   241  	_, err = dec.Decode()
   242  	c.Check(err, check.Equals, io.EOF)
   243  }
   244  
   245  func (s *assertsSuite) TestAssertsFindManyNoResults(c *check.C) {
   246  	acct := assertstest.NewAccount(s.storeSigning, "developer1", nil, "")
   247  	s.addAsserts(acct)
   248  
   249  	// Execute
   250  	req, err := http.NewRequest("POST", "/v2/assertions/account?username=xyzzyx", nil)
   251  	c.Assert(err, check.IsNil)
   252  	defer daemon.MockMuxVars(func(*http.Request) map[string]string {
   253  		return map[string]string{"assertType": "account"}
   254  	})()
   255  
   256  	rec := httptest.NewRecorder()
   257  	daemon.AssertsFindManyCmd.GET(daemon.AssertsFindManyCmd, req, nil).ServeHTTP(rec, req)
   258  	// Verify
   259  	c.Check(rec.Code, check.Equals, 200, check.Commentf("body %q", rec.Body))
   260  	c.Check(rec.HeaderMap.Get("X-Ubuntu-Assertions-Count"), check.Equals, "0")
   261  	dec := asserts.NewDecoder(rec.Body)
   262  	_, err = dec.Decode()
   263  	c.Check(err, check.Equals, io.EOF)
   264  }
   265  
   266  func (s *assertsSuite) TestAssertsInvalidType(c *check.C) {
   267  	// Execute
   268  	req, err := http.NewRequest("POST", "/v2/assertions/foo", nil)
   269  	c.Assert(err, check.IsNil)
   270  	defer daemon.MockMuxVars(func(*http.Request) map[string]string {
   271  		return map[string]string{"assertType": "foo"}
   272  	})()
   273  
   274  	rec := httptest.NewRecorder()
   275  	daemon.AssertsFindManyCmd.GET(daemon.AssertsFindManyCmd, req, nil).ServeHTTP(rec, req)
   276  	// Verify
   277  	c.Check(rec.Code, check.Equals, 400)
   278  	c.Check(rec.Body.String(), testutil.Contains, "invalid assert type")
   279  }
   280  
   281  func (s *assertsSuite) TestAssertsFindManyJSONFilter(c *check.C) {
   282  	s.testAssertsFindManyJSONFilter(c, "/v2/assertions/account?json=true&username=developer1")
   283  }
   284  
   285  func (s *assertsSuite) TestAssertsFindManyJSONFilterRemoteIsFalse(c *check.C) {
   286  	// setting "remote=false" is the defalt and should not change anything
   287  	s.testAssertsFindManyJSONFilter(c, "/v2/assertions/account?json=true&username=developer1&remote=false")
   288  }
   289  
   290  func (s *assertsSuite) testAssertsFindManyJSONFilter(c *check.C, urlPath string) {
   291  	acct := assertstest.NewAccount(s.storeSigning, "developer1", nil, "")
   292  	s.addAsserts(acct)
   293  
   294  	// Execute
   295  	req, err := http.NewRequest("POST", urlPath, nil)
   296  	c.Assert(err, check.IsNil)
   297  	defer daemon.MockMuxVars(func(*http.Request) map[string]string {
   298  		return map[string]string{"assertType": "account"}
   299  	})()
   300  
   301  	rec := httptest.NewRecorder()
   302  	daemon.AssertsFindManyCmd.GET(daemon.AssertsFindManyCmd, req, nil).ServeHTTP(rec, req)
   303  	// Verify
   304  	c.Check(rec.Code, check.Equals, 200, check.Commentf("body %q", rec.Body))
   305  	c.Check(rec.HeaderMap.Get("Content-Type"), check.Equals, "application/json")
   306  
   307  	var body map[string]interface{}
   308  	err = json.Unmarshal(rec.Body.Bytes(), &body)
   309  	c.Assert(err, check.IsNil)
   310  	c.Check(body["result"], check.DeepEquals, []interface{}{
   311  		map[string]interface{}{
   312  			"headers": acct.Headers(),
   313  		},
   314  	})
   315  }
   316  
   317  func (s *assertsSuite) TestAssertsFindManyJSONNoResults(c *check.C) {
   318  	acct := assertstest.NewAccount(s.storeSigning, "developer1", nil, "")
   319  	s.addAsserts(acct)
   320  
   321  	// Execute
   322  	req, err := http.NewRequest("POST", "/v2/assertions/account?json=true&username=xyz", nil)
   323  	c.Assert(err, check.IsNil)
   324  	defer daemon.MockMuxVars(func(*http.Request) map[string]string {
   325  		return map[string]string{"assertType": "account"}
   326  	})()
   327  
   328  	rec := httptest.NewRecorder()
   329  	daemon.AssertsFindManyCmd.GET(daemon.AssertsFindManyCmd, req, nil).ServeHTTP(rec, req)
   330  	// Verify
   331  	c.Check(rec.Code, check.Equals, 200, check.Commentf("body %q", rec.Body))
   332  	c.Check(rec.HeaderMap.Get("Content-Type"), check.Equals, "application/json")
   333  
   334  	var body map[string]interface{}
   335  	err = json.Unmarshal(rec.Body.Bytes(), &body)
   336  	c.Assert(err, check.IsNil)
   337  	c.Check(body["result"], check.DeepEquals, []interface{}{})
   338  }
   339  
   340  func (s *assertsSuite) TestAssertsFindManyJSONWithBody(c *check.C) {
   341  	// add store key
   342  	s.addAsserts()
   343  
   344  	// Execute
   345  	req, err := http.NewRequest("POST", "/v2/assertions/account-key?json=true", nil)
   346  	c.Assert(err, check.IsNil)
   347  	defer daemon.MockMuxVars(func(*http.Request) map[string]string {
   348  		return map[string]string{"assertType": "account-key"}
   349  	})()
   350  
   351  	rec := httptest.NewRecorder()
   352  	daemon.AssertsFindManyCmd.GET(daemon.AssertsFindManyCmd, req, nil).ServeHTTP(rec, req)
   353  	// Verify
   354  	c.Check(rec.Code, check.Equals, 200, check.Commentf("body %q", rec.Body))
   355  	c.Check(rec.HeaderMap.Get("Content-Type"), check.Equals, "application/json")
   356  
   357  	var got []string
   358  	var body map[string]interface{}
   359  	err = json.Unmarshal(rec.Body.Bytes(), &body)
   360  	c.Assert(err, check.IsNil)
   361  	for _, a := range body["result"].([]interface{}) {
   362  		h := a.(map[string]interface{})["headers"].(map[string]interface{})
   363  		got = append(got, h["account-id"].(string)+"/"+h["name"].(string))
   364  		// check body
   365  		l, err := strconv.Atoi(h["body-length"].(string))
   366  		c.Assert(err, check.IsNil)
   367  		c.Check(a.(map[string]interface{})["body"], check.HasLen, l)
   368  	}
   369  	sort.Strings(got)
   370  	c.Check(got, check.DeepEquals, []string{"can0nical/root", "can0nical/store", "canonical/root", "generic/models"})
   371  }
   372  
   373  func (s *assertsSuite) TestAssertsFindManyJSONHeadersOnly(c *check.C) {
   374  	// add store key
   375  	s.addAsserts()
   376  
   377  	// Execute
   378  	req, err := http.NewRequest("POST", "/v2/assertions/account-key?json=headers&account-id=can0nical", nil)
   379  	c.Assert(err, check.IsNil)
   380  	defer daemon.MockMuxVars(func(*http.Request) map[string]string {
   381  		return map[string]string{"assertType": "account-key"}
   382  	})()
   383  
   384  	rec := httptest.NewRecorder()
   385  	daemon.AssertsFindManyCmd.GET(daemon.AssertsFindManyCmd, req, nil).ServeHTTP(rec, req)
   386  	// Verify
   387  	c.Check(rec.Code, check.Equals, 200, check.Commentf("body %q", rec.Body))
   388  	c.Check(rec.HeaderMap.Get("Content-Type"), check.Equals, "application/json")
   389  
   390  	var got []string
   391  	var body map[string]interface{}
   392  	err = json.Unmarshal(rec.Body.Bytes(), &body)
   393  	c.Assert(err, check.IsNil)
   394  	for _, a := range body["result"].([]interface{}) {
   395  		h := a.(map[string]interface{})["headers"].(map[string]interface{})
   396  		got = append(got, h["account-id"].(string)+"/"+h["name"].(string))
   397  		// check body absent
   398  		_, ok := a.(map[string]interface{})["body"]
   399  		c.Assert(ok, check.Equals, false)
   400  	}
   401  	sort.Strings(got)
   402  	c.Check(got, check.DeepEquals, []string{"can0nical/root", "can0nical/store"})
   403  }
   404  
   405  func (s *assertsSuite) TestAssertsFindManyJSONInvalidParam(c *check.C) {
   406  	// add store key
   407  	s.addAsserts()
   408  
   409  	// Execute
   410  	req, err := http.NewRequest("POST", "/v2/assertions/account-key?json=header&account-id=can0nical", nil)
   411  	c.Assert(err, check.IsNil)
   412  	defer daemon.MockMuxVars(func(*http.Request) map[string]string {
   413  		return map[string]string{"assertType": "account-key"}
   414  	})()
   415  
   416  	rec := httptest.NewRecorder()
   417  	daemon.AssertsFindManyCmd.GET(daemon.AssertsFindManyCmd, req, nil).ServeHTTP(rec, req)
   418  	// Verify
   419  	c.Check(rec.Code, check.Equals, 400, check.Commentf("body %q", rec.Body))
   420  	c.Check(rec.HeaderMap.Get("Content-Type"), check.Equals, "application/json")
   421  
   422  	var rsp daemon.Resp
   423  	c.Assert(json.Unmarshal(rec.Body.Bytes(), &rsp), check.IsNil)
   424  	c.Check(rsp.Status, check.Equals, 400)
   425  	c.Check(rsp.Type, check.Equals, daemon.ResponseTypeError)
   426  	c.Check(rsp.Result, check.DeepEquals, map[string]interface{}{
   427  		"message": `"json" query parameter when used must be set to "true" or "headers"`,
   428  	})
   429  }
   430  
   431  func (s *assertsSuite) TestAssertsFindManyJSONNopFilter(c *check.C) {
   432  	acct := assertstest.NewAccount(s.storeSigning, "developer1", nil, "")
   433  	s.addAsserts(acct)
   434  
   435  	// Execute
   436  	req, err := http.NewRequest("POST", "/v2/assertions/account?json=false&username=developer1", nil)
   437  	c.Assert(err, check.IsNil)
   438  	defer daemon.MockMuxVars(func(*http.Request) map[string]string {
   439  		return map[string]string{"assertType": "account"}
   440  	})()
   441  
   442  	rec := httptest.NewRecorder()
   443  	daemon.AssertsFindManyCmd.GET(daemon.AssertsFindManyCmd, req, nil).ServeHTTP(rec, req)
   444  	// Verify
   445  	c.Check(rec.Code, check.Equals, 200, check.Commentf("body %q", rec.Body))
   446  	c.Check(rec.HeaderMap.Get("X-Ubuntu-Assertions-Count"), check.Equals, "1")
   447  	dec := asserts.NewDecoder(rec.Body)
   448  	a1, err := dec.Decode()
   449  	c.Assert(err, check.IsNil)
   450  	c.Check(a1.Type(), check.Equals, asserts.AccountType)
   451  	c.Check(a1.(*asserts.Account).Username(), check.Equals, "developer1")
   452  	c.Check(a1.(*asserts.Account).AccountID(), check.Equals, acct.AccountID())
   453  	_, err = dec.Decode()
   454  	c.Check(err, check.Equals, io.EOF)
   455  }
   456  
   457  func (s *assertsSuite) TestAssertsFindManyRemoteInvalidParam(c *check.C) {
   458  	// Execute
   459  	req, err := http.NewRequest("POST", "/v2/assertions/account-key?remote=invalid&account-id=can0nical", nil)
   460  	c.Assert(err, check.IsNil)
   461  	defer daemon.MockMuxVars(func(*http.Request) map[string]string {
   462  		return map[string]string{"assertType": "account-key"}
   463  	})()
   464  
   465  	rec := httptest.NewRecorder()
   466  	daemon.AssertsFindManyCmd.GET(daemon.AssertsFindManyCmd, req, nil).ServeHTTP(rec, req)
   467  	// Verify
   468  	c.Check(rec.Code, check.Equals, 400, check.Commentf("body %q", rec.Body))
   469  	c.Check(rec.HeaderMap.Get("Content-Type"), check.Equals, "application/json")
   470  	var rsp daemon.Resp
   471  	c.Assert(json.Unmarshal(rec.Body.Bytes(), &rsp), check.IsNil)
   472  	c.Check(rsp.Status, check.Equals, 400)
   473  	c.Check(rsp.Type, check.Equals, daemon.ResponseTypeError)
   474  	c.Check(rsp.Result, check.DeepEquals, map[string]interface{}{
   475  		"message": `"remote" query parameter when used must be set to "true" or "false" or left unset`,
   476  	})
   477  }
   478  
   479  func (s *assertsSuite) Assertion(at *asserts.AssertionType, headers []string, user *auth.UserState) (asserts.Assertion, error) {
   480  	return s.mockAssertionFn(at, headers, user)
   481  }
   482  
   483  func (s *assertsSuite) TestAssertsFindManyRemote(c *check.C) {
   484  	var assertFnCalled int
   485  	s.mockAssertionFn = func(at *asserts.AssertionType, headers []string, user *auth.UserState) (asserts.Assertion, error) {
   486  		assertFnCalled++
   487  		c.Assert(at.Name, check.Equals, "account")
   488  		c.Assert(headers, check.DeepEquals, []string{"can0nical"})
   489  		return assertstest.NewAccount(s.storeSigning, "some-developer", nil, ""), nil
   490  	}
   491  
   492  	acct := assertstest.NewAccount(s.storeSigning, "developer1", nil, "")
   493  	s.addAsserts(acct)
   494  
   495  	// Execute
   496  	req, err := http.NewRequest("POST", "/v2/assertions/account?remote=true&account-id=can0nical", nil)
   497  	c.Assert(err, check.IsNil)
   498  	defer daemon.MockMuxVars(func(*http.Request) map[string]string {
   499  		return map[string]string{"assertType": "account"}
   500  	})()
   501  
   502  	rec := httptest.NewRecorder()
   503  	daemon.AssertsFindManyCmd.GET(daemon.AssertsFindManyCmd, req, nil).ServeHTTP(rec, req)
   504  	// Verify
   505  	c.Check(assertFnCalled, check.Equals, 1)
   506  	c.Check(rec.Code, check.Equals, 200, check.Commentf("body %q", rec.Body))
   507  	c.Check(rec.HeaderMap.Get("Content-Type"), check.Equals, "application/x.ubuntu.assertion; bundle=y")
   508  
   509  	data := rec.Body.Bytes()
   510  	c.Check(string(data), check.Matches, `(?ms)type: account
   511  authority-id: can0nical
   512  account-id: [a-zA-Z0-9]+
   513  display-name: Some-developer
   514  timestamp: .*
   515  username: some-developer
   516  validation: unproven
   517  .*
   518  `)
   519  
   520  }