-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support snap store proxy setup via the snap-store-proxy-url config opt.
- Loading branch information
1 parent
59cbe59
commit ee10204
Showing
13 changed files
with
275 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// Copyright 2019 Canonical Ltd. | ||
// Licensed under the AGPLv3, see LICENCE file for details. | ||
|
||
package snap | ||
|
||
import ( | ||
"context" | ||
"io/ioutil" | ||
"net/http" | ||
"net/url" | ||
"regexp" | ||
"time" | ||
|
||
"github.com/juju/errors" | ||
) | ||
|
||
// LookupAssertions attempts to download an assertion list from the snap store | ||
// proxy located at proxyURL and locate the store ID associated with the | ||
// specified proxyURL. | ||
// | ||
// If the local snap store proxy instance is operating in an air-gapped | ||
// environment, downloading the assertion list from the proxy will not be | ||
// possible and an appropriate error will be returned. | ||
func LookupAssertions(proxyURL string) (assertions, storeID string, err error) { | ||
u, err := url.Parse(proxyURL) | ||
if err != nil { | ||
return "", "", errors.Annotate(err, "proxy URL not valid") | ||
} | ||
if u.Scheme != "http" && u.Scheme != "https" { | ||
return "", "", errors.NotValidf("proxy URL scheme %q", u.Scheme) | ||
} | ||
|
||
// Make sure to redact user/pass when including the proxy URL in error messages | ||
u.User = nil | ||
noCredsProxyURL := u.String() | ||
|
||
pathURL, _ := url.Parse("/v2/auth/store/assertions") | ||
req, _ := http.NewRequest("GET", u.ResolveReference(pathURL).String(), nil) | ||
ctx, cancelFn := context.WithTimeout(context.Background(), 30*time.Second) | ||
defer cancelFn() | ||
|
||
res, err := http.DefaultClient.Do(req.WithContext(ctx)) | ||
if err != nil { | ||
return "", "", errors.Annotatef(err, "could not contact snap store proxy at %q. If using an air-gapped proxy you must manually provide the assertions file and store ID", noCredsProxyURL) | ||
} | ||
defer func() { _ = res.Body.Close() }() | ||
if res.StatusCode != http.StatusOK { | ||
return "", "", errors.Annotatef(err, "could not retrieve assertions from proxy at %q; proxy replied with unexpected HTTP status code %d", noCredsProxyURL, res.StatusCode) | ||
} | ||
|
||
data, err := ioutil.ReadAll(res.Body) | ||
if err != nil { | ||
return "", "", errors.Annotatef(err, "could not read assertions response from proxy at %q", noCredsProxyURL) | ||
} | ||
assertions = string(data) | ||
if storeID, err = findStoreID(assertions, u); err != nil { | ||
return "", "", errors.Trace(err) | ||
} | ||
|
||
return assertions, storeID, nil | ||
} | ||
|
||
var storeInAssertionRE = regexp.MustCompile(`(?is)type: store.*?store: ([a-zA-Z0-9]+).*?url: (https?://[^\s]+)`) | ||
|
||
func findStoreID(assertions string, proxyURL *url.URL) (string, error) { | ||
var storeID string | ||
for _, match := range storeInAssertionRE.FindAllStringSubmatch(assertions, -1) { | ||
if len(match) != 3 { | ||
continue | ||
} | ||
|
||
// Found store assertion but not for the URL provided | ||
storeURL, err := url.Parse(match[2]) | ||
if err != nil { | ||
continue | ||
} | ||
if storeURL.Host != proxyURL.Host { | ||
continue | ||
} | ||
|
||
// Found same URL but different store ID | ||
if storeID != "" && match[1] != storeID { | ||
return "", errors.Errorf("assertions response from proxy at %q is ambiguous as it contains multiple entries with the same proxy URL but different store ID", proxyURL) | ||
} | ||
|
||
storeID = match[1] | ||
} | ||
|
||
if storeID == "" { | ||
return "", errors.NotFoundf("store ID in assertions response from proxy at %q", proxyURL) | ||
} | ||
|
||
return storeID, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
// Copyright 2019 Canonical Ltd. | ||
// Licensed under the AGPLv3, see LICENCE file for details. | ||
|
||
package snap_test | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
"net/http/httptest" | ||
"strings" | ||
|
||
"github.com/juju/juju/core/snap" | ||
gc "gopkg.in/check.v1" | ||
) | ||
|
||
var ( | ||
_ = gc.Suite(&SnapSuite{}) | ||
|
||
snapProxyResponse = ` | ||
type: account-key | ||
authority-id: canonical | ||
revision: 2 | ||
public-key-sha3-384: BWDEoaqyr25nF5SNCvEv2v7QnM9QsfCc0PBMYD_i2NGSQ32EF2d4D0hqUel3m8ul | ||
account-id: canonical | ||
name: store | ||
since: 2016-04-01T00:00:00.0Z | ||
body-length: 717 | ||
sign-key-sha3-384: -CvQKAwRQ5h3Ffn10FILJoEZUXOv6km9FwA80-Rcj-f-6jadQ89VRswHNiEB9Lxk | ||
DATA... | ||
MORE DATA... | ||
type: account | ||
authority-id: canonical | ||
account-id: 1234567890367OdMqoW9YLp3e0EgakQf | ||
display-name: John Doe | ||
timestamp: 2019-05-10T13:12:32.878905Z | ||
username: jdoe | ||
validation: unproven | ||
sign-key-sha3-384: BWDEoaqyr25nF5SNCvEv2v7QnM9QsfCc0PBMYD_i2NGSQ32EF2d4D0hqUel3m8ul | ||
DATA... | ||
type: store | ||
authority-id: canonical | ||
store: 1234567890STOREIDENTIFIER0123456 | ||
operator-id: 0123456789067OdMqoW9YLp3e0EgakQf | ||
timestamp: 2019-08-27T12:20:45.166790Z | ||
url: $store-url | ||
sign-key-sha3-384: BWDEoaqyr25nF5SNCvEv2v7QnM9QsfCc0PBMYD_i2NGSQ32EF2d4D0hqUel3m8ul | ||
DATA... | ||
DATA... | ||
type: store | ||
authority-id: canonical | ||
store: OTHER | ||
operator-id: 0123456789067OdMqoW9YLp3e0EgakQf | ||
timestamp: 2019-08-27T12:20:45.166790Z | ||
url: $other-url/ | ||
sign-key-sha3-384: BWDEoaqyr25nF5SNCvEv2v7QnM9QsfCc0PBMYD_i2NGSQ32EF2d4D0hqUel3m8ul | ||
DATA... | ||
DATA... | ||
` | ||
) | ||
|
||
type SnapSuite struct { | ||
} | ||
|
||
func (s *SnapSuite) TestLookupAssertions(c *gc.C) { | ||
var ( | ||
srv *httptest.Server | ||
assertionsRes string | ||
) | ||
srv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
_, _ = w.Write([]byte(assertionsRes)) | ||
})) | ||
assertionsRes = strings.Replace(snapProxyResponse, "$store-url", srv.URL, -1) | ||
defer srv.Close() | ||
|
||
assertions, storeID, err := snap.LookupAssertions(srv.URL) | ||
c.Assert(err, gc.IsNil) | ||
c.Assert(assertions, gc.Equals, assertionsRes) | ||
c.Assert(storeID, gc.Equals, "1234567890STOREIDENTIFIER0123456") | ||
} | ||
|
||
func (s *SnapSuite) TestConfigureProxyFromURLWithAmbiguousAssertions(c *gc.C) { | ||
var ( | ||
srv *httptest.Server | ||
assertionsRes string | ||
) | ||
srv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
_, _ = w.Write([]byte(assertionsRes)) | ||
})) | ||
assertionsRes = strings.Replace(snapProxyResponse, "$store-url", srv.URL, -1) | ||
assertionsRes = strings.Replace(assertionsRes, "$other-url", srv.URL, -1) | ||
defer srv.Close() | ||
|
||
// Make sure that we don't leak any credentials in error messages | ||
srvURLWithPassword := fmt.Sprintf("http://42:secret@%s", srv.Listener.Addr()) | ||
_, _, err := snap.LookupAssertions(srvURLWithPassword) | ||
expErr := fmt.Sprintf(`assertions response from proxy at "%s" is ambiguous as it contains multiple entries with the same proxy URL but different store ID`, srv.URL) | ||
c.Assert(err, gc.ErrorMatches, expErr) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// Copyright 2019 Canonical Ltd. | ||
// Licensed under the AGPLv3, see LICENCE file for details. | ||
|
||
package snap_test | ||
|
||
import ( | ||
"testing" | ||
|
||
gc "gopkg.in/check.v1" | ||
) | ||
|
||
func TestAll(t *testing.T) { | ||
gc.TestingT(t) | ||
} |
Oops, something went wrong.