restapi_test.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. package httpservers
  2. import (
  3. "crypto/rand"
  4. "crypto/rsa"
  5. "crypto/x509"
  6. "encoding/pem"
  7. "fmt"
  8. config "github.com/OliveTin/OliveTin/internal/config"
  9. "github.com/OliveTin/OliveTin/internal/cors"
  10. "github.com/golang-jwt/jwt/v4"
  11. "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
  12. "github.com/stretchr/testify/assert"
  13. "google.golang.org/protobuf/encoding/protojson"
  14. "io"
  15. "net"
  16. "net/http"
  17. "os"
  18. "testing"
  19. "time"
  20. )
  21. func createKeys() (*rsa.PrivateKey, string) {
  22. tmpFile, _ := os.CreateTemp(os.TempDir(), "olivetin-jwt-")
  23. defer os.Remove(tmpFile.Name())
  24. fmt.Println("Created File: " + tmpFile.Name())
  25. privateKey, _ := rsa.GenerateKey(rand.Reader, 2048)
  26. pubKey := &privateKey.PublicKey
  27. // https://stackoverflow.com/questions/13555085/save-and-load-crypto-rsa-privatekey-to-and-from-the-disk
  28. pkixPubKey, _ := x509.MarshalPKIXPublicKey(pubKey)
  29. pubPem := pem.EncodeToMemory(
  30. &pem.Block{
  31. Type: "RSA PUBLIC KEY",
  32. Bytes: pkixPubKey,
  33. },
  34. )
  35. if err := os.WriteFile(tmpFile.Name(), pubPem, 0755); err != nil {
  36. fmt.Printf("error when dumping pubKey: %s \n", err)
  37. }
  38. return privateKey, tmpFile.Name()
  39. }
  40. func testBase(t *testing.T, expire int64, expectCode int) {
  41. privateKey, publicKeyPath := createKeys()
  42. // default config + overrides
  43. cfg := config.DefaultConfig()
  44. cfg.AuthJwtPubKeyPath = publicKeyPath
  45. cfg.AuthJwtClaimUsername = "sub"
  46. cfg.AuthJwtClaimUserGroup = "olivetinGroup"
  47. cfg.AuthJwtCookieName = "authorization_token"
  48. SetGlobalRestConfig(cfg) // ugly, setting global var, we should pass configs as params to modules... :/
  49. token := jwt.New(jwt.SigningMethodRS256)
  50. claims := token.Claims.(jwt.MapClaims)
  51. claims["nbf"] = time.Now().Unix() - 1000
  52. claims["exp"] = time.Now().Unix() + expire
  53. claims["sub"] = "test"
  54. claims["olivetinGroup"] = "test"
  55. tokenStr, _ := token.SignedString(privateKey)
  56. // init mux endpoint like in restapi.go (but using dummy response handler)
  57. mux := runtime.NewServeMux(
  58. runtime.WithMetadata(parseRequestMetadata), // i am guessing this is critical middleware for authorizing request cookie
  59. runtime.WithMarshalerOption(runtime.MIMEWildcard, &runtime.HTTPBodyMarshaler{
  60. Marshaler: &runtime.JSONPb{
  61. MarshalOptions: protojson.MarshalOptions{
  62. UseProtoNames: true,
  63. EmitUnpopulated: true,
  64. },
  65. },
  66. }),
  67. )
  68. mux.HandlePath("GET", "/", func(w http.ResponseWriter, r *http.Request, pathParams map[string]string) {
  69. username, usergroup := parseJwtCookie(r)
  70. if username == "" {
  71. w.WriteHeader(403)
  72. }
  73. w.Write([]byte(fmt.Sprintf("username=%v, usergroup=%v", username, usergroup)))
  74. })
  75. // make server and attach handler
  76. setupTestingServer(mux, t)
  77. // make http client and send request to myself
  78. client := &http.Client{}
  79. req, _ := http.NewRequest("GET", "http://localhost:1337/", nil)
  80. cookie := &http.Cookie{
  81. Name: "authorization_token",
  82. Value: tokenStr,
  83. MaxAge: 300,
  84. }
  85. req.AddCookie(cookie)
  86. res, err := client.Do(req)
  87. if err != nil {
  88. assert.Equal(t, expectCode, -1)
  89. } else {
  90. defer res.Body.Close()
  91. assert.Equal(t, expectCode, res.StatusCode)
  92. body, _ := io.ReadAll(res.Body)
  93. fmt.Println(string(body))
  94. }
  95. }
  96. func setupTestingServer(mux *runtime.ServeMux, t *testing.T) {
  97. lis, err := net.Listen("tcp", ":1337")
  98. if err != nil || lis == nil {
  99. t.Errorf("Could not listen %v %v", err, lis)
  100. return
  101. }
  102. srv := &http.Server{Handler: cors.AllowCors(mux)}
  103. go startTestingServer(lis, srv, t)
  104. }
  105. func startTestingServer(lis net.Listener, srv *http.Server, t *testing.T) {
  106. if srv == nil {
  107. t.Errorf("srv is nil. Could not listen")
  108. return
  109. }
  110. go func() {
  111. if err := srv.Serve(lis); err != nil {
  112. t.Errorf("couldn't start server: %v", err)
  113. }
  114. }()
  115. }
  116. func TestJWTSignatureVerificationSucceeds(t *testing.T) {
  117. // testBase(t, 1000, 200)
  118. }
  119. func TestJWTSignatureVerificationFails(t *testing.T) {
  120. testBase(t, -500, 403)
  121. }