Skip to content

Commit

Permalink
Add tls option to websupport and add some testing functions
Browse files Browse the repository at this point in the history
  • Loading branch information
Dylan Ham committed Dec 8, 2022
1 parent 27f5888 commit dfa80cf
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 0 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ require (
github.com/prometheus/client_golang v1.12.1
github.com/stretchr/testify v1.7.0
google.golang.org/api v0.97.0
gopkg.in/square/go-jose.v2 v2.6.0
)

require (
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,8 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
Expand Down
157 changes: 157 additions & 0 deletions pkg/testsupport/fake_authserver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package testsupport

import (
"crypto/rand"
"crypto/rsa"
"encoding/json"
"fmt"
"log"
"net/http"
"net/http/httptest"
"net/url"
"time"

"gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/jwt"
)

type FakeAuthServer struct {
Issuer string
clientID string
claims map[string]interface{}
signingKey SigningKey
Server *httptest.Server
}

type SigningKey struct {
key *rsa.PrivateKey
id string
}

func NewFakeAuthServer(clientID string, claims map[string]interface{}) *FakeAuthServer {
k, _ := rsa.GenerateKey(rand.Reader, 2048)

authServer := &FakeAuthServer{
signingKey: SigningKey{
key: k,
id: "some-key-id",
},
clientID: clientID,
claims: claims,
}
mux := http.NewServeMux()
mux.HandleFunc("/.well-known/openid-configuration", authServer.handleWellKnown)
mux.HandleFunc("/authorize", authServer.handleAuthorize)
mux.HandleFunc("/token", authServer.handleToken)
mux.HandleFunc("/jwks", authServer.handleJWKS)

authServer.Server = httptest.NewServer(mux)
authServer.Issuer = authServer.Server.URL
return authServer
}

func (as *FakeAuthServer) handleWellKnown(rw http.ResponseWriter, r *http.Request) {
wellKnownConfig := struct {
Issuer string `json:"issuer,omitempty"`
AuthorizationEndpoint string `json:"authorization_endpoint,omitempty"`
TokenEndpoint string `json:"token_endpoint,omitempty"`
JWKSEndpoint string `json:"jwks_uri,omitempty"`
}{
Issuer: as.Issuer,
AuthorizationEndpoint: fmt.Sprintf("%s/authorize", as.Issuer),
TokenEndpoint: fmt.Sprintf("%s/token", as.Issuer),
JWKSEndpoint: fmt.Sprintf("%s/jwks", as.Issuer),
}
_ = json.NewEncoder(rw).Encode(wellKnownConfig)
}

func (as *FakeAuthServer) handleAuthorize(rw http.ResponseWriter, r *http.Request) {
state := r.URL.Query().Get("state")
redirect := r.URL.Query().Get("redirect_uri")

redirectURI, _ := url.Parse(redirect)
q := redirectURI.Query()
q.Set("code", "42")
q.Set("state", state)
redirectURI.RawQuery = q.Encode()

// todo - inject a way to assert authorize request made by client?

http.Redirect(rw, r, redirectURI.String(), http.StatusFound)
}

func (as *FakeAuthServer) handleToken(rw http.ResponseWriter, r *http.Request) {
_ = r.ParseForm()
if r.FormValue("code") != "42" {
http.Error(rw, fmt.Sprintf("invalid authorization code"), http.StatusBadRequest)
return
}

token, err := as.buildJWT()
if err != nil {
http.Error(rw, fmt.Sprintf("unable to build token: %s", err), http.StatusInternalServerError)
return
}

resp := struct {
AccessToken string `json:"access_token,omitempty"`
TokenType string `json:"token_type"`
IDToken string `json:"id_token,omitempty"`
}{
AccessToken: token,
TokenType: "Bearer",
IDToken: token,
}

rw.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(rw).Encode(resp)
}

func (as *FakeAuthServer) handleJWKS(rw http.ResponseWriter, _ *http.Request) {
jwk := jose.JSONWebKey{
Key: as.signingKey.key.Public(),
KeyID: as.signingKey.id,
Algorithm: "RS256",
Use: "sig",
}
var keys []jose.JSONWebKey
keys = append(keys, jwk)

jwks := jose.JSONWebKeySet{
Keys: keys,
}
rw.Header().Set("Content-Type", "application/json")
err := json.NewEncoder(rw).Encode(jwks)
if err != nil {
log.Println("unable to encode jwks: ", err.Error())
}
}

func (as *FakeAuthServer) buildJWT() (string, error) {
issuedAt := time.Now()
expiresAt := issuedAt.Add(time.Minute)

regClaims := jwt.Claims{
Issuer: as.Issuer,
Audience: jwt.Audience{as.clientID},
Subject: as.clientID,
Expiry: jwt.NewNumericDate(expiresAt),
IssuedAt: jwt.NewNumericDate(issuedAt),
}

sk := jose.SigningKey{Algorithm: jose.RS256, Key: as.signingKey.key}
so := (&jose.SignerOptions{}).
WithType("at+jwt").
WithHeader("kid", as.signingKey.id)
signer, err := jose.NewSigner(sk, so)
if err != nil {
return "", fmt.Errorf("failed to initialize signer: %w", err)
}

raw, err := jwt.Signed(signer).Claims(regClaims).Claims(as.claims).CompactSerialize()
if err != nil {
return "", fmt.Errorf("failed to sign claims: %w", err)
}

return raw, nil
}
7 changes: 7 additions & 0 deletions pkg/testsupport/test_support.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,10 @@ func WithSetUp[T TestData](data T, test func(data T)) {
test(data)
data.TearDown()
}

func AssertExists(file []byte, err error) []byte {
if err != nil {
panic("unable to read file.")
}
return file
}
20 changes: 20 additions & 0 deletions pkg/websupport/web_support.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package websupport

import (
"context"
"crypto/tls"
"log"
"net"
"net/http"
"os"

"github.com/gorilla/mux"
"github.com/hexa-org/policy-orchestrator/pkg/healthsupport"
Expand Down Expand Up @@ -80,3 +82,21 @@ func Stop(server *http.Server) {
log.Printf("Stopping the server.")
_ = server.Shutdown(context.Background())
}

func WithTransportLayerSecurity(certFile, keyFile string, app *http.Server) {
cert, certErr := os.ReadFile(certFile)
if certErr != nil {
panic(certErr.Error())
}
key, keyErr := os.ReadFile(keyFile)
if keyErr != nil {
panic(certErr.Error())
}
pair, pairErr := tls.X509KeyPair(cert, key)
if pairErr != nil {
panic(pairErr.Error())
}
app.TLSConfig = &tls.Config{
Certificates: []tls.Certificate{pair},
}
}

0 comments on commit dfa80cf

Please sign in to comment.