Skip to content
This repository was archived by the owner on Jun 20, 2024. It is now read-only.

Commit 965d25e

Browse files
authored
Merge pull request #249 from neicnordic/feature/use-gin-router
Replace mux with gin router
2 parents a5f3579 + ab892a7 commit 965d25e

File tree

13 files changed

+239
-178
lines changed

13 files changed

+239
-178
lines changed

.github/integration/tests/common/50_check_endpoint.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ fi
5959

6060
echo "expected dataset found"
6161

62-
## Test datasets/files endpoint
62+
## Test datasets/files endpoint
6363

6464
check_files=$(curl --cacert certs/ca.pem -H "Authorization: Bearer $token" "https://localhost:8443/metadata/datasets/https://doi.example/ty009.sfrrss/600.45asasga/files" | jq -r '.[0].fileId')
6565

@@ -91,7 +91,7 @@ else
9191
fi
9292

9393
# ------------------
94-
# Test bad token
94+
# Test get visas failed
9595

9696
token=$(curl --cacert certs/ca.pem "https://localhost:8000/tokens" | jq -r '.[1]')
9797

.github/integration/tests/s3notls/52_check_endpoint.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ fi
5555

5656
echo "expected dataset found"
5757

58-
## Test datasets/files endpoint
58+
## Test datasets/files endpoint
5959

6060
check_files=$(curl -H "Authorization: Bearer $token" "http://localhost:8080/metadata/datasets/https://doi.example/ty009.sfrrss/600.45asasga/files" | jq -r '.[0].fileId')
6161

@@ -78,7 +78,7 @@ crypt4gh decrypt --sk c4gh.sec.pem < dummy_data.c4gh > old-file.txt
7878
curl -H "Authorization: Bearer $token" "http://localhost:8080/files/urn:neic:001-002" --output test-download.txt
7979

8080

81-
cmp --silent old-file.txt test-download.txt
81+
cmp --silent old-file.txt test-download.txt
8282
status=$?
8383
if [[ $status = 0 ]]; then
8484
echo "Files are the same"
@@ -87,7 +87,7 @@ else
8787
fi
8888

8989
# ------------------
90-
# Test bad token
90+
# Test get visas failed
9191

9292
token=$(curl --cacert certs/ca.pem "https://localhost:8000/tokens" | jq -r '.[1]')
9393

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ There is an README file in the [dev_utils](/dev_utils) folder with sections for
2626
| Component | Role |
2727
|---------------|------|
2828
| middleware | Performs access token verification and validation |
29-
| sda | Constructs the main API endpoints fort the NeIC SDA Data Out API. |
29+
| sda | Constructs the main API endpoints for the NeIC SDA Data Out API. |
3030

3131

3232
## Internal Components
@@ -43,4 +43,4 @@ There is an README file in the [dev_utils](/dev_utils) folder with sections for
4343
| Component | Role |
4444
|---------------|------|
4545
| auth | Auth pkg is used by the middleware to parse OIDC Details and extract GA4GH Visas from a [GA4GH Passport](https://github.com/ga4gh-duri/ga4gh-duri.github.io/blob/master/researcher_ids/ga4gh_passport_v1.md) |
46-
| request | This pkg Stores a HTTP client, so that it doesn't need to be initialised on every request. |
46+
| request | This pkg Stores a HTTP client, so that it doesn't need to be initialised on every request. |

api/api.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,32 @@ import (
66
"net/http"
77
"time"
88

9-
"github.com/gorilla/mux"
9+
"github.com/gin-gonic/gin"
1010
"github.com/neicnordic/sda-download/api/middleware"
1111
"github.com/neicnordic/sda-download/api/sda"
1212
"github.com/neicnordic/sda-download/internal/config"
1313
log "github.com/sirupsen/logrus"
1414
)
1515

1616
// healthResponse
17-
func healthResponse(w http.ResponseWriter, r *http.Request) {
17+
func healthResponse(c *gin.Context) {
1818
// ok response to health
19-
w.WriteHeader(http.StatusOK)
19+
c.Writer.WriteHeader(http.StatusOK)
2020
}
2121

2222
// Setup configures the web server and registers the routes
2323
func Setup() *http.Server {
2424
// Set up routing
2525
log.Info("(2/5) Registering endpoint handlers")
26-
r := mux.NewRouter().SkipClean(true)
2726

28-
r.Handle("/metadata/datasets", middleware.TokenMiddleware(http.HandlerFunc(sda.Datasets))).Methods("GET")
29-
r.Handle("/metadata/datasets/{dataset:[^\\s/$.?#].[^\\s]+|[A-Za-z0-9-_:.]+}/files", middleware.TokenMiddleware(http.HandlerFunc(sda.Files))).Methods("GET")
30-
r.Handle("/files/{fileid:[A-Za-z0-9-_:.]+}", middleware.TokenMiddleware(http.HandlerFunc(sda.Download))).Methods("GET")
31-
r.HandleFunc("/health", healthResponse).Methods("GET")
27+
router := gin.Default()
28+
29+
router.HandleMethodNotAllowed = true
30+
31+
router.GET("/metadata/datasets", middleware.TokenMiddleware(), sda.Datasets)
32+
router.GET("/metadata/datasets/*dataset", middleware.TokenMiddleware(), sda.Files)
33+
router.GET("/files/:fileid", middleware.TokenMiddleware(), sda.Download)
34+
router.GET("/health", healthResponse)
3235

3336
// Configure TLS settings
3437
log.Info("(3/5) Configuring TLS")
@@ -45,7 +48,7 @@ func Setup() *http.Server {
4548
log.Info("(4/5) Configuring server")
4649
srv := &http.Server{
4750
Addr: config.Config.App.Host + ":" + fmt.Sprint(config.Config.App.Port),
48-
Handler: r,
51+
Handler: router,
4952
TLSConfig: cfg,
5053
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
5154
ReadHeaderTimeout: 20 * time.Second,

api/middleware/middleware.go

Lines changed: 29 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,43 @@
11
package middleware
22

33
import (
4-
"context"
54
"net/http"
65

6+
"github.com/gin-gonic/gin"
77
"github.com/neicnordic/sda-download/internal/config"
88
"github.com/neicnordic/sda-download/internal/session"
99
"github.com/neicnordic/sda-download/pkg/auth"
1010
log "github.com/sirupsen/logrus"
1111
)
1212

13-
type stringVariable string
14-
15-
// as specified in docs: https://pkg.go.dev/context#WithValue
16-
var datasetsKey = stringVariable("datasets")
13+
var datasetsKey = "datasets"
1714

1815
// TokenMiddleware performs access token verification and validation
1916
// JWTs are verified and validated by the app, opaque tokens are sent to AAI for verification
2017
// Successful auth results in list of authorised datasets
21-
func TokenMiddleware(nextHandler http.Handler) http.Handler {
22-
23-
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
18+
func TokenMiddleware() gin.HandlerFunc {
2419

20+
return func(c *gin.Context) {
2521
// Check if dataset permissions are cached to session
26-
sessionCookie, err := r.Cookie(config.Config.Session.Name)
22+
sessionCookie, err := c.Cookie(config.Config.Session.Name)
2723
if err != nil {
2824
log.Debugf("no session cookie received")
2925
}
3026
var datasets []string
3127
var exists bool
32-
if sessionCookie != nil {
28+
if sessionCookie != "" {
3329
log.Debug("session cookie received")
34-
datasets, exists = session.Get(sessionCookie.Value)
30+
datasets, exists = session.Get(sessionCookie)
3531
}
3632

3733
if !exists {
3834
log.Debug("no session found, create new session")
3935

4036
// Check that a token is provided
41-
token, code, err := auth.GetToken(r.Header.Get("Authorization"))
37+
token, code, err := auth.GetToken(c.Request.Header.Get("Authorization"))
4238
if err != nil {
43-
http.Error(w, err.Error(), code)
39+
c.String(code, err.Error())
40+
c.AbortWithStatus(code)
4441

4542
return
4643
}
@@ -49,7 +46,8 @@ func TokenMiddleware(nextHandler http.Handler) http.Handler {
4946
visas, err := auth.GetVisas(auth.Details, token)
5047
if err != nil {
5148
log.Debug("failed to validate token at AAI")
52-
http.Error(w, "bad token", 401)
49+
c.String(http.StatusUnauthorized, "get visas failed")
50+
c.AbortWithStatus(code)
5351

5452
return
5553
}
@@ -64,47 +62,40 @@ func TokenMiddleware(nextHandler http.Handler) http.Handler {
6462
// Start a new session and store datasets under the session key
6563
key := session.NewSessionKey()
6664
session.Set(key, datasets)
67-
sessionCookie := &http.Cookie{
68-
Name: config.Config.Session.Name,
69-
Value: key,
70-
Domain: config.Config.Session.Domain,
71-
Secure: config.Config.Session.Secure,
72-
HttpOnly: config.Config.Session.HTTPOnly,
73-
// time.Duration is stored in nanoseconds, but MaxAge wants seconds
74-
MaxAge: int(config.Config.Session.Expiration) / 1e9,
75-
}
76-
http.SetCookie(w, sessionCookie)
65+
c.SetCookie(config.Config.Session.Name, // name
66+
key, // value
67+
int(config.Config.Session.Expiration)/1e9, // max age
68+
"/", // path
69+
config.Config.Session.Domain, // domain
70+
config.Config.Session.Secure, // secure
71+
config.Config.Session.HTTPOnly, // httpOnly
72+
)
7773
log.Debug("authorization check passed")
7874
}
7975

8076
// Store dataset list to request context, for use in the endpoint handlers
81-
modifiedContext := storeDatasets(r.Context(), datasets)
82-
modifiedRequest := r.WithContext(modifiedContext)
77+
c = storeDatasets(c, datasets)
8378

8479
// Forward request to the next endpoint handler
85-
nextHandler.ServeHTTP(w, modifiedRequest)
86-
})
80+
c.Next()
81+
}
8782

8883
}
8984

9085
// storeDatasets stores the dataset list to the request context
91-
func storeDatasets(ctx context.Context, datasets []string) context.Context {
86+
func storeDatasets(c *gin.Context, datasets []string) *gin.Context {
9287
log.Debugf("storing %v datasets to request context", datasets)
9388

94-
ctx = context.WithValue(ctx, datasetsKey, datasets)
89+
c.Set(datasetsKey, datasets)
9590

96-
return ctx
91+
return c
9792
}
9893

9994
// GetDatasets extracts the dataset list from the request context
100-
var GetDatasets = func(ctx context.Context) []string {
101-
datasets := ctx.Value(datasetsKey)
102-
if datasets == nil {
103-
log.Debug("request datasets context is empty")
95+
var GetDatasets = func(c *gin.Context) []string {
96+
datasets := c.GetStringSlice(datasetsKey)
10497

105-
return []string{}
106-
}
10798
log.Debugf("returning %v from request context", datasets)
10899

109-
return datasets.([]string)
100+
return datasets
110101
}

0 commit comments

Comments
 (0)