1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
|
package cautils
import (
"encoding/json"
"io"
"net/http"
"net/url"
"strings"
"github.com/smallstep/certificates/pki"
"github.com/smallstep/cli/exec"
"github.com/urfave/cli"
"github.com/pkg/errors"
)
type bootstrapAPIResponse struct {
CaURL string `json:"url"`
Fingerprint string `json:"fingerprint"`
RedirectURL string `json:"redirect-url"`
}
// BootstrapTeam does a request to api.smallstep.com to bootstrap the
// configuration of the given team ID (slug).
func BootstrapTeam(ctx *cli.Context, teamID string) error {
apiEndpoint := ctx.String("team-url")
if apiEndpoint == "" {
// Use the default endpoint..
u := url.URL{
Scheme: "https",
Host: "api.smallstep.com",
Path: "/v1/teams/" + teamID + "/authorities/ssh",
}
apiEndpoint = u.String()
} else {
// The user specified a custom endpoint..
apiEndpoint = strings.ReplaceAll(apiEndpoint, "<>", teamID)
u, err := url.Parse(apiEndpoint)
if err != nil {
return errors.Wrapf(err, "error parsing %s", apiEndpoint)
}
apiEndpoint = u.String()
}
// Using public PKI
resp, err := http.Get(apiEndpoint)
if err != nil {
return errors.Wrap(err, "error getting team data")
}
if resp.StatusCode >= 400 {
if resp.StatusCode == http.StatusNotFound {
return errors.New("error getting team data: team not found")
}
return errors.Wrap(readError(resp.Body), "error getting team data")
}
var r bootstrapAPIResponse
if err := readJSON(resp.Body, &r); err != nil {
return errors.Wrap(err, "error getting team data")
}
if r.RedirectURL == "" {
r.RedirectURL = "https://smallstep.com/app/teams/sso/success"
}
args := []string{"ca", "bootstrap",
"--ca-url", r.CaURL,
"--fingerprint", r.Fingerprint,
"--redirect-url", r.RedirectURL,
}
if ctx.Bool("force") {
args = append(args, "--force")
}
if _, err := exec.Step(args...); err != nil {
return errors.Wrap(err, "error getting team data")
}
// Set ca-url and root certificate
ctx.Set("ca-url", r.CaURL)
ctx.Set("fingerprint", r.Fingerprint)
ctx.Set("root", pki.GetRootCAPath())
return nil
}
type apiError struct {
StatusCode int `json:"statusCode"`
Err string `json:"error"`
Message string `json:"message"`
}
func (e *apiError) Error() string {
return e.Message
}
func readJSON(r io.ReadCloser, v interface{}) error {
defer r.Close()
if err := json.NewDecoder(r).Decode(v); err != nil {
return err
}
return nil
}
func readError(r io.ReadCloser) error {
defer r.Close()
apiErr := new(apiError)
if err := json.NewDecoder(r).Decode(apiErr); err != nil {
return err
}
return apiErr
}
|