1
0
mirror of https://github.com/coreos/ignition.git synced 2026-02-06 09:47:17 +01:00
Files
ignition/tests/servers/servers.go
2024-10-14 15:33:52 +02:00

302 lines
9.1 KiB
Go

// Copyright 2018 CoreOS, Inc.
//
// 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 servers
import (
"bytes"
"compress/gzip"
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
"fmt"
"io"
"net/http"
"os"
"strings"
"time"
"github.com/coreos/ignition/v2/tests/fixtures"
"github.com/pin/tftp"
)
var (
servedConfig = []byte(`{
"ignition": { "version": "3.0.0" },
"storage": {
"files": [{
"path": "/foo/bar",
"contents": { "source": "data:,example%20file%0A" }
}]
}
}`)
servedContents = []byte(`asdf
fdsa`)
// export these so tests don't have to hard-code them everywhere
configRawHash = sha512.Sum512(servedConfig)
contentsRawHash = sha512.Sum512(servedContents)
publicKeyRawHash = sha512.Sum512(fixtures.PublicKey)
configRawHashForSHA256 = sha256.Sum256(servedConfig)
contentsRawHashForSHA256 = sha256.Sum256(servedContents)
publicKeyRawHashForSHA256 = sha256.Sum256(fixtures.PublicKey)
ConfigHash = hex.EncodeToString(configRawHash[:])
ContentsHash = hex.EncodeToString(contentsRawHash[:])
PublicKeyHash = hex.EncodeToString(publicKeyRawHash[:])
ConfigHashForSHA256 = hex.EncodeToString(configRawHashForSHA256[:])
ContentsHashForSHA256 = hex.EncodeToString(contentsRawHashForSHA256[:])
PublicKeyHashForSHA256 = hex.EncodeToString(publicKeyRawHashForSHA256[:])
)
// HTTP Server
func (server *HTTPServer) Config(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write(servedConfig)
}
func (server *HTTPServer) Contents(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write(servedContents)
}
func (server *HTTPServer) Certificates(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write(fixtures.PublicKey)
}
func (server *HTTPServer) CABundle(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write(fixtures.CABundle)
}
func compress(contents []byte) []byte {
var buf bytes.Buffer
w := gzip.NewWriter(&buf)
if _, err := w.Write(contents); err != nil {
panic(err)
}
if err := w.Close(); err != nil {
panic(err)
}
return buf.Bytes()
}
func (server *HTTPServer) ConfigCompressed(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write(compress(servedConfig))
}
func (server *HTTPServer) ContentsCompressed(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write(compress(servedContents))
}
func (server *HTTPServer) CertificatesCompressed(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write(compress(fixtures.PublicKey))
}
func errorHandler(w http.ResponseWriter, message string) {
w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write([]byte(message))
}
// headerCheck validates that all required headers are present
func headerCheck(w http.ResponseWriter, r *http.Request) {
headers := map[string]string{
"X-Auth": "r8ewap98gfh4d8",
"Keep-Alive": "300",
"Accept": "application/vnd.coreos.ignition+json;version=3.5.0, */*;q=0.1",
"Accept-Encoding": "identity",
}
for headerName, headerValue := range headers {
if val, ok := r.Header[headerName]; ok {
if val[0] != headerValue {
errorHandler(w, headerName+" header value is incorrect")
return
}
} else {
errorHandler(w, headerName+" header is missing")
return
}
}
if val, ok := r.Header["User-Agent"]; ok {
if !strings.HasPrefix(val[0], "Ignition/") {
errorHandler(w, "User-Agent header value is incorrect")
return
}
} else {
errorHandler(w, "User-Agent header is missing")
return
}
}
func overwrittenHeaderCheck(w http.ResponseWriter, r *http.Request) {
headers := map[string]string{
"Keep-Alive": "1000",
"Accept": "application/json",
"Accept-Encoding": "identity, compress",
"User-Agent": "MyUA",
}
for headerName, headerValue := range headers {
if val, ok := r.Header[headerName]; ok {
if val[0] != headerValue {
errorHandler(w, headerName+" header value is incorrect")
return
}
} else {
errorHandler(w, headerName+" header is missing")
return
}
}
}
func (server *HTTPServer) ConfigHeaders(w http.ResponseWriter, r *http.Request) {
headerCheck(w, r)
_, _ = w.Write(servedConfig)
}
func (server *HTTPServer) ContentsHeaders(w http.ResponseWriter, r *http.Request) {
headerCheck(w, r)
_, _ = w.Write(servedContents)
}
func (server *HTTPServer) CertificatesHeaders(w http.ResponseWriter, r *http.Request) {
headerCheck(w, r)
_, _ = w.Write(fixtures.PublicKey)
}
// redirectedHeaderCheck validates that user's headers from the original request are missing
func redirectedHeaderCheck(w http.ResponseWriter, r *http.Request) {
if _, ok := r.Header["X-Auth"]; ok {
errorHandler(w, "Found redundant header X-Auth")
return
}
if _, ok := r.Header["Keep-Alive"]; ok {
errorHandler(w, "Found redundant header Keep-Alive")
return
}
}
// ConfigRedirect redirects the request to ConfigRedirected
func (server *HTTPServer) ConfigRedirect(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "http://127.0.0.1:8080/config_headers_redirected", http.StatusFound)
}
// ConfigRedirected validates the request from ConfigRedirect
func (server *HTTPServer) ConfigRedirected(w http.ResponseWriter, r *http.Request) {
redirectedHeaderCheck(w, r)
_, _ = w.Write(servedConfig)
}
// ContentsRedirect redirects the request to ContentsRedirected
func (server *HTTPServer) ContentsRedirect(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "http://127.0.0.1:8080/contents_headers_redirected", http.StatusFound)
}
// ContentsRedirected validates the request from ContentsRedirect
func (server *HTTPServer) ContentsRedirected(w http.ResponseWriter, r *http.Request) {
redirectedHeaderCheck(w, r)
_, _ = w.Write(servedContents)
}
// CertificatesRedirect redirects the request to CertificatesRedirected
func (server *HTTPServer) CertificatesRedirect(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "http://127.0.0.1:8080/certificates_headers_redirected", http.StatusFound)
}
// CertificatesRedirected validates the request from CertificatesRedirect
func (server *HTTPServer) CertificatesRedirected(w http.ResponseWriter, r *http.Request) {
redirectedHeaderCheck(w, r)
_, _ = w.Write(fixtures.PublicKey)
}
func (server *HTTPServer) ConfigHeadersOverwrite(w http.ResponseWriter, r *http.Request) {
overwrittenHeaderCheck(w, r)
_, _ = w.Write(servedConfig)
}
func (server *HTTPServer) ContentsHeadersOverwrite(w http.ResponseWriter, r *http.Request) {
overwrittenHeaderCheck(w, r)
_, _ = w.Write(servedContents)
}
func (server *HTTPServer) CertificatesHeadersOverwrite(w http.ResponseWriter, r *http.Request) {
overwrittenHeaderCheck(w, r)
_, _ = w.Write(fixtures.PublicKey)
}
type HTTPServer struct{}
func (server *HTTPServer) Start() {
http.HandleFunc("/contents", server.Contents)
http.HandleFunc("/contents_compressed", server.ContentsCompressed)
http.HandleFunc("/contents_headers", server.ContentsHeaders)
http.HandleFunc("/contents_headers_redirect", server.ContentsRedirect)
http.HandleFunc("/contents_headers_redirected", server.ContentsRedirected)
http.HandleFunc("/contents_headers_overwrite", server.ContentsHeadersOverwrite)
http.HandleFunc("/certificates", server.Certificates)
http.HandleFunc("/certificates_compressed", server.CertificatesCompressed)
http.HandleFunc("/certificates_headers", server.CertificatesHeaders)
http.HandleFunc("/certificates_headers_redirect", server.CertificatesRedirect)
http.HandleFunc("/certificates_headers_redirected", server.CertificatesRedirected)
http.HandleFunc("/certificates_headers_overwrite", server.CertificatesHeadersOverwrite)
http.HandleFunc("/config", server.Config)
http.HandleFunc("/config_compressed", server.ConfigCompressed)
http.HandleFunc("/config_headers", server.ConfigHeaders)
http.HandleFunc("/config_headers_redirect", server.ConfigRedirect)
http.HandleFunc("/config_headers_redirected", server.ConfigRedirected)
http.HandleFunc("/config_headers_overwrite", server.ConfigHeadersOverwrite)
http.HandleFunc("/caBundle", server.CABundle)
s := &http.Server{Addr: ":8080"}
go func() {
_ = s.ListenAndServe()
}()
}
// TFTP Server
func (server *TFTPServer) ReadHandler(filename string, rf io.ReaderFrom) error {
var buf *bytes.Reader
if strings.Contains(filename, "contents") {
buf = bytes.NewReader(servedContents)
} else if strings.Contains(filename, "config") {
buf = bytes.NewReader(servedConfig)
} else {
return fmt.Errorf("no such file %q", filename)
}
_, err := rf.ReadFrom(buf)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return err
}
return nil
}
type TFTPServer struct{}
func (server *TFTPServer) Start() {
s := tftp.NewServer(server.ReadHandler, nil)
s.SetTimeout(5 * time.Second)
go func() {
_ = s.ListenAndServe(":69")
}()
}