Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 29 additions & 4 deletions acceptance/acceptance_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package acceptance_test

import (
"bytes"
"encoding/json"
"log"
"net"
"net/http"
"net/url"
"os"
"source-score/pkg/api"
"source-score/pkg/helpers"
Expand Down Expand Up @@ -32,10 +34,14 @@ const (
)

var (
baseUrl string
commonHeaders = map[string]string{"X-API-Key": "demo-api-key"}
client = &http.Client{Timeout: 10 * time.Second}
serverPort = os.Getenv("PORT")
baseUrl string
token string

commonHeaders = map[string]string{
"Client-ID": "ac-tests",
}
client = &http.Client{Timeout: 10 * time.Second}
serverPort = os.Getenv("PORT")
sourceInput1 = api.SourceInput{
Name: "Sample Source 1",
Summary: "Sample summary",
Expand Down Expand Up @@ -130,6 +136,25 @@ func TestSourceScore(t *testing.T) {

baseUrl = "http://" + helpers.Localhost + ":" + serverPort

var _ = BeforeSuite(func() {
endpoint, err := url.JoinPath(baseUrl, "/auth/token")
Expect(err).To(BeNil())

resp, err := doRequest(http.MethodPost, endpoint, nil)
Expect(err).To(BeNil())
Expect(resp.StatusCode).To(Equal(http.StatusOK))

defer resp.Body.Close()
var tokenResp map[string]string
err = json.NewDecoder(resp.Body).Decode(&tokenResp)
Expect(err).To(BeNil())

token = tokenResp["token"]
Expect(token).ToNot(Equal(""))

commonHeaders["Authorization"] = "Bearer " + token
})

RegisterFailHandler(Fail)
RunSpecs(t, "SourceScore Acceptance Test Suite")
}
Expand Down
92 changes: 92 additions & 0 deletions acceptance/auth_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package acceptance_test

import (
"net/http"
"net/url"
"source-score/pkg/middleware"
"time"

"github.com/golang-jwt/jwt/v5"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = Describe("Auth middleware tests", func() {
protectedEndpoint, err := url.JoinPath(baseUrl, "/api/v1/claims")
Expect(err).To(BeNil())

Comment thread
semmet95 marked this conversation as resolved.
Outdated
XContext("Validation tests", func() {
Comment thread
semmet95 marked this conversation as resolved.
Outdated
Comment thread
semmet95 marked this conversation as resolved.
Outdated
It("should reject requests with an invalid jwt token", func() {
resp, err := doRequestWithAuthToken(http.MethodGet, protectedEndpoint, "invalid.jwt.token")
Expect(err).To(BeNil())
defer resp.Body.Close()

Expect(resp.StatusCode).To(Equal(http.StatusUnauthorized))
})

It("should reject requests with an expired jwt token", func() {
token := signAcceptanceToken(jwt.RegisteredClaims{
Audience: []string{commonHeaders[middleware.ClientIDHeader]},
ExpiresAt: jwt.NewNumericDate(time.Now().Add(-time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now().Add(-2 * time.Hour)),
Issuer: middleware.TokenIssuer,
})

resp, err := doRequestWithAuthToken(http.MethodPost, protectedEndpoint, token)
Expect(err).To(BeNil())
defer resp.Body.Close()

Expect(resp.StatusCode).To(Equal(http.StatusUnauthorized))
})

It("should reject requests when jwt audience does not match the client id header", func() {
token := signAcceptanceToken(jwt.RegisteredClaims{
Audience: []string{"another-client"},
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
Issuer: middleware.TokenIssuer,
})

resp, err := doRequestWithAuthToken(http.MethodPost, protectedEndpoint, token)
Expect(err).To(BeNil())
defer resp.Body.Close()

Expect(resp.StatusCode).To(Equal(http.StatusUnauthorized))
})

It("should reject requests when jwt issuer does not match the configured token issuer", func() {
token := signAcceptanceToken(jwt.RegisteredClaims{
Audience: []string{commonHeaders[middleware.ClientIDHeader]},
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
Issuer: "another-issuer",
})

resp, err := doRequestWithAuthToken(http.MethodPost, protectedEndpoint, token)
Expect(err).To(BeNil())
defer resp.Body.Close()

Expect(resp.StatusCode).To(Equal(http.StatusUnauthorized))
})
})
})

func doRequestWithAuthToken(method, endpoint, authToken string) (*http.Response, error) {
req, err := http.NewRequest(method, endpoint, nil)
if err != nil {
return nil, err
}

req.Header.Set(middleware.ClientIDHeader, commonHeaders[middleware.ClientIDHeader])
req.Header.Set("Authorization", "Bearer "+authToken)

return client.Do(req)
}

func signAcceptanceToken(claims jwt.RegisteredClaims) string {
// signing secret is the same as that hardcoded for app container in docker compose
signedToken, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte("default-secret-string"))
Expect(err).To(BeNil())

return signedToken
}
2 changes: 1 addition & 1 deletion acceptance/compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ services:
- APP_USER_PASSWORD=sourcescore
- PG_HOST=database
- SUPER_USER_PASSWORD=sourcescore
- API_KEY=demo-api-key
- RATE_LIMIT_DISABLED=true
- JWT_SECRET=default-secret-string
ports:
- "8080:8080"
adminer:
Expand Down
Loading
Loading