mirror of
https://github.com/clearlinux/rkt.git
synced 2026-08-25 17:45:49 +00:00
9685f37575
Inspired by a similar change in the Kubernetes project [1], this changes the copyright header to the more generic "The rkt Authors" rather than "CoreOS, Inc.", which is only sometimes correct. https://github.com/GoogleCloudPlatform/kubernetes/commit/6b3a6e6b983f967c88d14d26542ec6e30c49ebd3
256 lines
5.6 KiB
Go
256 lines
5.6 KiB
Go
// Copyright 2015 The rkt Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package aci
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
type Type int
|
|
|
|
const (
|
|
None Type = iota
|
|
Basic
|
|
Oauth
|
|
)
|
|
|
|
type httpError struct {
|
|
code int
|
|
message string
|
|
}
|
|
|
|
func (e *httpError) Error() string {
|
|
return fmt.Sprintf("%d: %s", e.code, e.message)
|
|
}
|
|
|
|
type serverHandler struct {
|
|
auth Type
|
|
stop chan<- struct{}
|
|
msg chan<- string
|
|
tools *aciToolkit
|
|
}
|
|
|
|
func (h *serverHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
switch r.Method {
|
|
case "POST":
|
|
w.WriteHeader(http.StatusOK)
|
|
h.stop <- struct{}{}
|
|
return
|
|
case "GET":
|
|
// handled later
|
|
default:
|
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
switch h.auth {
|
|
case None:
|
|
// no auth to do.
|
|
case Basic:
|
|
payload, httpErr := getAuthPayload(r, "Basic")
|
|
if httpErr != nil {
|
|
w.WriteHeader(httpErr.code)
|
|
h.sendMsg(fmt.Sprintf(`No "Authorization" header: %v`, httpErr.message))
|
|
return
|
|
}
|
|
creds, err := base64.StdEncoding.DecodeString(string(payload))
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
h.sendMsg(fmt.Sprintf(`Badly formed "Authorization" header`))
|
|
return
|
|
}
|
|
parts := strings.Split(string(creds), ":")
|
|
if len(parts) != 2 {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
h.sendMsg(fmt.Sprintf(`Badly formed "Authorization" header (2)`))
|
|
return
|
|
}
|
|
user := parts[0]
|
|
password := parts[1]
|
|
if user != "bar" || password != "baz" {
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
h.sendMsg(fmt.Sprintf("Bad credentials: %q", string(creds)))
|
|
return
|
|
}
|
|
case Oauth:
|
|
payload, httpErr := getAuthPayload(r, "Bearer")
|
|
if httpErr != nil {
|
|
w.WriteHeader(httpErr.code)
|
|
h.sendMsg(fmt.Sprintf(`No "Authorization" header: %v`, httpErr.message))
|
|
return
|
|
}
|
|
if payload != "sometoken" {
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
h.sendMsg(fmt.Sprintf(`Bad token: %q`, payload))
|
|
return
|
|
}
|
|
default:
|
|
panic("Woe is me!")
|
|
}
|
|
h.sendMsg(fmt.Sprintf("Trying to serve %q", r.URL.String()))
|
|
switch filepath.Base(r.URL.Path) {
|
|
case "prog.aci":
|
|
h.sendMsg(fmt.Sprintf(" serving"))
|
|
if data, err := h.tools.prepareACI(); err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
h.sendMsg(fmt.Sprintf(" failed (%v)", err))
|
|
} else {
|
|
w.Write(data)
|
|
h.sendMsg(fmt.Sprintf(" done."))
|
|
}
|
|
default:
|
|
h.sendMsg(fmt.Sprintf(" not found."))
|
|
w.WriteHeader(http.StatusNotFound)
|
|
}
|
|
}
|
|
|
|
func (h *serverHandler) sendMsg(msg string) {
|
|
select {
|
|
case h.msg <- msg:
|
|
default:
|
|
}
|
|
}
|
|
|
|
func getAuthPayload(r *http.Request, authType string) (string, *httpError) {
|
|
auth := r.Header.Get("Authorization")
|
|
if auth == "" {
|
|
err := &httpError{
|
|
code: http.StatusUnauthorized,
|
|
message: "No auth",
|
|
}
|
|
return "", err
|
|
}
|
|
parts := strings.Split(auth, " ")
|
|
if len(parts) != 2 {
|
|
err := &httpError{
|
|
code: http.StatusBadRequest,
|
|
message: "Malformed auth",
|
|
}
|
|
return "", err
|
|
}
|
|
if parts[0] != authType {
|
|
err := &httpError{
|
|
code: http.StatusUnauthorized,
|
|
message: "Wrong auth",
|
|
}
|
|
return "", err
|
|
}
|
|
return parts[1], nil
|
|
}
|
|
|
|
type Server struct {
|
|
Stop <-chan struct{}
|
|
Msg <-chan string
|
|
Conf string
|
|
URL string
|
|
handler *serverHandler
|
|
http *httptest.Server
|
|
}
|
|
|
|
func (s *Server) Close() {
|
|
s.http.Close()
|
|
close(s.handler.msg)
|
|
close(s.handler.stop)
|
|
}
|
|
|
|
func NewServer(auth Type, msgCapacity int) (*Server, error) {
|
|
return NewServerWithPaths(auth, msgCapacity, "actool", "go")
|
|
}
|
|
|
|
func NewServerWithPaths(auth Type, msgCapacity int, acTool, goTool string) (*Server, error) {
|
|
if !filepath.IsAbs(acTool) {
|
|
absAcTool, err := getTool(acTool)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
acTool = absAcTool
|
|
}
|
|
if !filepath.IsAbs(goTool) {
|
|
absGoTool, err := getTool(goTool)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
goTool = absGoTool
|
|
}
|
|
stop := make(chan struct{})
|
|
msg := make(chan string, msgCapacity)
|
|
server := &Server{
|
|
Stop: stop,
|
|
Msg: msg,
|
|
handler: &serverHandler{
|
|
auth: auth,
|
|
stop: stop,
|
|
msg: msg,
|
|
tools: &aciToolkit{
|
|
acTool: acTool,
|
|
goTool: goTool,
|
|
},
|
|
},
|
|
}
|
|
server.http = httptest.NewUnstartedServer(server.handler)
|
|
server.http.TLS = &tls.Config{InsecureSkipVerify: true}
|
|
server.http.StartTLS()
|
|
server.URL = server.http.URL
|
|
host := server.http.Listener.Addr().String()
|
|
switch auth {
|
|
case None:
|
|
// nothing to do
|
|
case Basic:
|
|
creds := `"user": "bar",
|
|
"password": "baz"`
|
|
server.Conf = sprintCreds(host, "basic", creds)
|
|
case Oauth:
|
|
creds := `"token": "sometoken"`
|
|
server.Conf = sprintCreds(host, "oauth", creds)
|
|
default:
|
|
panic("Woe is me!")
|
|
}
|
|
return server, nil
|
|
}
|
|
|
|
func getTool(tool string) (string, error) {
|
|
toolPath, err := exec.LookPath(tool)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to find %s in $PATH: %v", tool, err)
|
|
}
|
|
absToolPath, err := filepath.Abs(toolPath)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to get absolute path of %s: %v", tool, err)
|
|
}
|
|
return absToolPath, nil
|
|
}
|
|
|
|
func sprintCreds(host, auth, creds string) string {
|
|
return fmt.Sprintf(`
|
|
{
|
|
"rktKind": "auth",
|
|
"rktVersion": "v1",
|
|
"domains": ["%s"],
|
|
"type": "%s",
|
|
"credentials":
|
|
{
|
|
%s
|
|
}
|
|
}
|
|
|
|
`, host, auth, creds)
|
|
}
|