Merge pull request #22 from jkaninda/develop

Develop
This commit is contained in:
2024-10-30 22:17:37 +01:00
committed by GitHub
11 changed files with 237 additions and 215 deletions

View File

@@ -145,46 +145,12 @@ gateway:
Access-Control-Allow-Headers: 'Origin, Authorization, Accept, Content-Type, Access-Control-Allow-Headers, X-Client-Id, X-Session-Id' Access-Control-Allow-Headers: 'Origin, Authorization, Accept, Content-Type, Access-Control-Allow-Headers, X-Client-Id, X-Session-Id'
Access-Control-Allow-Credentials: 'true' Access-Control-Allow-Credentials: 'true'
Access-Control-Max-Age: 1728000 Access-Control-Max-Age: 1728000
#### Define route blocklist paths
blocklist:
- /swagger-ui/*
- /v2/swagger-ui/*
- /api-docs/*
- /internal/*
- /actuator/*
##### Define route middlewares from middlewares names ##### Define route middlewares from middlewares names
## The name must be unique ## The name must be unique
## List of middleware name ## List of middleware name
middlewares: middlewares:
# path to protect - api-forbidden-paths
- path: /user
# Rules defines which specific middleware applies to a route path
rules:
- basic-auth - basic-auth
# path to protect
- path: /path-example
# Rules defines which specific middleware applies to a route path
rules:
- jwt
# path to protect
- path: /admin
# Rules defines which specific middleware applies to a route path
rules:
- basic-auth
# path to protect
- path: /path-example
# Rules defines which specific middleware applies to a route path
rules:
- jwt
- path: /history
http:
url: http://security-service:8080/security/authUser
headers:
#Key from backend authentication header, and inject to the request with custom key name
userId: X-Auth-UserId
userCountryId: X-Auth-UserCountryId
params:
userCountryId: X-countryId
# Example of a route | 2 # Example of a route | 2
- name: Authentication service - name: Authentication service
path: /auth path: /auth
@@ -192,8 +158,8 @@ gateway:
destination: 'http://security-service:8080' destination: 'http://security-service:8080'
healthCheck: /internal/health/ready healthCheck: /internal/health/ready
cors: {} cors: {}
blocklist: [] middlewares:
middlewares: [] - api-forbidden-paths
# Example of a route | 3 # Example of a route | 3
- name: Basic auth - name: Basic auth
path: /protected path: /protected
@@ -201,7 +167,6 @@ gateway:
destination: 'http://notification-service:8080' destination: 'http://notification-service:8080'
healthCheck: healthCheck:
cors: {} cors: {}
blocklist: []
middlewares: [] middlewares: []
#Defines proxy middlewares #Defines proxy middlewares
@@ -210,6 +175,10 @@ middlewares:
- name: basic-auth - name: basic-auth
# Authentication types | jwt, basic, OAuth # Authentication types | jwt, basic, OAuth
type: basic type: basic
paths:
- /user
- /admin
- /account
rule: rule:
username: admin username: admin
password: admin password: admin
@@ -218,6 +187,10 @@ middlewares:
# Authentication types | jwt, basic, OAuth # Authentication types | jwt, basic, OAuth
# jwt authorization based on the result of backend's response and continue the request when the client is authorized # jwt authorization based on the result of backend's response and continue the request when the client is authorized
type: jwt type: jwt
# Paths to protect
paths:
- /protected-access
- /example-of-jwt
rule: rule:
# This is an example URL # This is an example URL
url: https://www.googleapis.com/auth/userinfo.email url: https://www.googleapis.com/auth/userinfo.email
@@ -240,6 +213,16 @@ middlewares:
# In case you want to get headers from the Authentication service and inject them to the next request's params # In case you want to get headers from the Authentication service and inject them to the next request's params
params: params:
userCountryId: countryId userCountryId: countryId
# The server will return 404
- name: api-forbidden-paths
type: access
## Forbidden paths
paths:
- /swagger-ui/*
- /v2/swagger-ui/*
- /api-docs/*
- /internal/*
- /actuator/*
``` ```
## Requirement ## Requirement

View File

@@ -66,46 +66,12 @@ gateway:
Access-Control-Allow-Headers: 'Origin, Authorization, Accept, Content-Type, Access-Control-Allow-Headers, X-Client-Id, X-Session-Id' Access-Control-Allow-Headers: 'Origin, Authorization, Accept, Content-Type, Access-Control-Allow-Headers, X-Client-Id, X-Session-Id'
Access-Control-Allow-Credentials: 'true' Access-Control-Allow-Credentials: 'true'
Access-Control-Max-Age: 1728000 Access-Control-Max-Age: 1728000
#### Define route blocklist paths
blocklist:
- /swagger-ui/*
- /v2/swagger-ui/*
- /api-docs/*
- /internal/*
- /actuator/*
##### Define route middlewares from middlewares names ##### Define route middlewares from middlewares names
## The name must be unique ## The name must be unique
## List of middleware name ## List of middleware name
middlewares: middlewares:
# path to protect - api-forbidden-paths
- path: /user
# Rules defines which specific middleware applies to a route path
rules:
- basic-auth - basic-auth
# path to protect
- path: /path-example
# Rules defines which specific middleware applies to a route path
rules:
- jwt
# path to protect
- path: /admin
# Rules defines which specific middleware applies to a route path
rules:
- basic-auth
# path to protect
- path: /path-example
# Rules defines which specific middleware applies to a route path
rules:
- jwt
- path: /history
http:
url: http://security-service:8080/security/authUser
headers:
#Key from backend authentication header, and inject to the request with custom key name
userId: X-Auth-UserId
userCountryId: X-Auth-UserCountryId
params:
userCountryId: X-countryId
# Example of a route | 2 # Example of a route | 2
- name: Authentication service - name: Authentication service
path: /auth path: /auth
@@ -113,8 +79,8 @@ gateway:
destination: 'http://security-service:8080' destination: 'http://security-service:8080'
healthCheck: /internal/health/ready healthCheck: /internal/health/ready
cors: {} cors: {}
blocklist: [] middlewares:
middlewares: [] - api-forbidden-paths
# Example of a route | 3 # Example of a route | 3
- name: Basic auth - name: Basic auth
path: /protected path: /protected
@@ -122,15 +88,19 @@ gateway:
destination: 'http://notification-service:8080' destination: 'http://notification-service:8080'
healthCheck: healthCheck:
cors: {} cors: {}
blocklist: []
middlewares: [] middlewares: []
#Defines proxy middlewares #Defines proxy middlewares
# middleware name must be unique
middlewares: middlewares:
# Enable Basic auth authorization based # Enable Basic auth authorization based
- name: basic-auth - name: basic-auth
# Authentication types | jwt, basic, OAuth # Authentication types | jwt, basic, OAuth
type: basic type: basic
paths:
- /user
- /admin
- /account
rule: rule:
username: admin username: admin
password: admin password: admin
@@ -139,6 +109,10 @@ middlewares:
# Authentication types | jwt, basic, OAuth # Authentication types | jwt, basic, OAuth
# jwt authorization based on the result of backend's response and continue the request when the client is authorized # jwt authorization based on the result of backend's response and continue the request when the client is authorized
type: jwt type: jwt
# Paths to protect
paths:
- /protected-access
- /example-of-jwt
rule: rule:
# This is an example URL # This is an example URL
url: https://www.googleapis.com/auth/userinfo.email url: https://www.googleapis.com/auth/userinfo.email
@@ -161,3 +135,13 @@ middlewares:
# In case you want to get headers from the Authentication service and inject them to the next request's params # In case you want to get headers from the Authentication service and inject them to the next request's params
params: params:
userCountryId: countryId userCountryId: countryId
# The server will return 404
- name: api-forbidden-paths
type: access
## Forbidden paths
paths:
- /swagger-ui/*
- /v2/swagger-ui/*
- /api-docs/*
- /internal/*
- /actuator/*

View File

@@ -77,9 +77,9 @@ func Debug(msg string, args ...interface{}) {
log.SetOutput(getStd(util.GetStringEnv("GOMA_ACCESS_LOG", "/dev/stdout"))) log.SetOutput(getStd(util.GetStringEnv("GOMA_ACCESS_LOG", "/dev/stdout")))
formattedMessage := fmt.Sprintf(msg, args...) formattedMessage := fmt.Sprintf(msg, args...)
if len(args) == 0 { if len(args) == 0 {
log.Printf("DUBUG: %s\n", msg) log.Printf("DEBUG: %s\n", msg)
} else { } else {
log.Printf("DUBUG: %s\n", formattedMessage) log.Printf("DEBUG: %s\n", formattedMessage)
} }
} }
func getStd(out string) *os.File { func getStd(out string) *os.File {

View File

@@ -30,7 +30,7 @@ var cfg *Gateway
type Config struct { type Config struct {
file string file string
} }
type BasicRule struct { type BasicRuleMiddleware struct {
Username string `yaml:"username"` Username string `yaml:"username"`
Password string `yaml:"password"` Password string `yaml:"password"`
} }
@@ -54,10 +54,10 @@ type Cors struct {
Headers map[string]string `yaml:"headers"` Headers map[string]string `yaml:"headers"`
} }
// JWTRuler authentication using HTTP GET method // JWTRuleMiddleware authentication using HTTP GET method
// //
// JWTRuler contains the authentication details // JWTRuleMiddleware contains the authentication details
type JWTRuler struct { type JWTRuleMiddleware struct {
// URL contains the authentication URL, it supports HTTP GET method only. // URL contains the authentication URL, it supports HTTP GET method only.
URL string `yaml:"url"` URL string `yaml:"url"`
// RequiredHeaders , contains required before sending request to the backend. // RequiredHeaders , contains required before sending request to the backend.
@@ -84,26 +84,25 @@ type RateLimiter struct {
Rule int `yaml:"rule"` Rule int `yaml:"rule"`
} }
type AccessRuleMiddleware struct {
ResponseCode int `yaml:"responseCode"` // HTTP Response code
}
// Middleware defined the route middleware // Middleware defined the route middleware
type Middleware struct { type Middleware struct {
//Path contains the name of middleware and must be unique //Path contains the name of middleware and must be unique
Name string `yaml:"name"` Name string `yaml:"name"`
// Type contains authentication types // Type contains authentication types
// //
// basic, jwt, auth0, rateLimit // basic, jwt, auth0, rateLimit, access
Type string `yaml:"type"` Type string `yaml:"type"` // Middleware type [basic, jwt, auth0, rateLimit, access]
Paths []string `yaml:"paths"` // Protected paths
// Rule contains rule type of // Rule contains rule type of
Rule interface{} `yaml:"rule"` Rule interface{} `yaml:"rule"` // Middleware rule
} }
type MiddlewareName struct { type MiddlewareName struct {
name string `yaml:"name"` name string `yaml:"name"`
} }
type RouteMiddleware struct {
//Path contains the path to protect
Path string `yaml:"path"`
//Rules defines which specific middleware applies to a route path
Rules []string `yaml:"rules"`
}
// Route defines gateway route // Route defines gateway route
type Route struct { type Route struct {
@@ -129,14 +128,12 @@ type Route struct {
DisableHeaderXForward bool `yaml:"disableHeaderXForward"` DisableHeaderXForward bool `yaml:"disableHeaderXForward"`
// HealthCheck Defines the backend is health check PATH // HealthCheck Defines the backend is health check PATH
HealthCheck string `yaml:"healthCheck"` HealthCheck string `yaml:"healthCheck"`
// Blocklist Defines route blacklist
Blocklist []string `yaml:"blocklist"`
// InterceptErrors intercepts backend errors based on the status codes // InterceptErrors intercepts backend errors based on the status codes
// //
// Eg: [ 403, 405, 500 ] // Eg: [ 403, 405, 500 ]
InterceptErrors []int `yaml:"interceptErrors"` InterceptErrors []int `yaml:"interceptErrors"`
// Middlewares Defines route middleware from Middleware names // Middlewares Defines route middleware from Middleware names
Middlewares []RouteMiddleware `yaml:"middlewares"` Middlewares []string `yaml:"middlewares"`
} }
// Gateway contains Goma Proxy Gateway's configs // Gateway contains Goma Proxy Gateway's configs
@@ -278,7 +275,6 @@ func initConfig(configFile string) {
Destination: "https://example.com", Destination: "https://example.com",
Rewrite: "/", Rewrite: "/",
HealthCheck: "", HealthCheck: "",
Blocklist: []string{},
Cors: Cors{ Cors: Cors{
Origins: []string{"http://localhost:3000", "https://dev.example.com"}, Origins: []string{"http://localhost:3000", "https://dev.example.com"},
Headers: map[string]string{ Headers: map[string]string{
@@ -287,12 +283,7 @@ func initConfig(configFile string) {
"Access-Control-Max-Age": "1728000", "Access-Control-Max-Age": "1728000",
}, },
}, },
Middlewares: []RouteMiddleware{ Middlewares: []string{"basic-auth", "api-forbidden-paths"},
{
Path: "/user",
Rules: []string{"basic-auth"},
},
},
}, },
{ {
Name: "Hostname example", Name: "Hostname example",
@@ -307,15 +298,24 @@ func initConfig(configFile string) {
Middlewares: []Middleware{ Middlewares: []Middleware{
{ {
Name: "basic-auth", Name: "basic-auth",
Type: "basic", Type: BasicAuth,
Rule: BasicRule{ Paths: []string{
"/user",
"/admin",
"/account",
},
Rule: BasicRuleMiddleware{
Username: "goma", Username: "goma",
Password: "goma", Password: "goma",
}, },
}, { }, {
Name: "jwt", Name: "jwt",
Type: "jwt", Type: JWTAuth,
Rule: JWTRuler{ Paths: []string{
"/protected-access",
"/example-of-jwt",
},
Rule: JWTRuleMiddleware{
URL: "https://www.googleapis.com/auth/userinfo.email", URL: "https://www.googleapis.com/auth/userinfo.email",
RequiredHeaders: []string{ RequiredHeaders: []string{
"Authorization", "Authorization",
@@ -324,6 +324,17 @@ func initConfig(configFile string) {
Params: map[string]string{}, Params: map[string]string{},
}, },
}, },
{
Name: "api-forbidden-paths",
Type: AccessMiddleware,
Paths: []string{
"/swagger-ui/*",
"/v2/swagger-ui/*",
"/api-docs/*",
"/internal/*",
"/actuator/*",
},
},
}, },
} }
yamlData, err := yaml.Marshal(&conf) yamlData, err := yaml.Marshal(&conf)
@@ -361,40 +372,40 @@ func (Gateway) Setup(conf string) *Gateway {
return &Gateway{} return &Gateway{}
} }
func (middleware Middleware) name() {
} // getJWTMiddleware returns JWTRuleMiddleware,error
func ToJWTRuler(input interface{}) (JWTRuler, error) { func getJWTMiddleware(input interface{}) (JWTRuleMiddleware, error) {
jWTRuler := new(JWTRuler) jWTRuler := new(JWTRuleMiddleware)
var bytes []byte var bytes []byte
bytes, err := yaml.Marshal(input) bytes, err := yaml.Marshal(input)
if err != nil { if err != nil {
return JWTRuler{}, fmt.Errorf("error parsing yaml: %v", err) return JWTRuleMiddleware{}, fmt.Errorf("error parsing yaml: %v", err)
} }
err = yaml.Unmarshal(bytes, jWTRuler) err = yaml.Unmarshal(bytes, jWTRuler)
if err != nil { if err != nil {
return JWTRuler{}, fmt.Errorf("error parsing yaml: %v", err) return JWTRuleMiddleware{}, fmt.Errorf("error parsing yaml: %v", err)
} }
if jWTRuler.URL == "" { if jWTRuler.URL == "" {
return JWTRuler{}, fmt.Errorf("error parsing yaml: empty url in jwt auth middleware") return JWTRuleMiddleware{}, fmt.Errorf("error parsing yaml: empty url in jwt auth middleware")
} }
return *jWTRuler, nil return *jWTRuler, nil
} }
func ToBasicAuth(input interface{}) (BasicRule, error) { // getBasicAuthMiddleware returns BasicRuleMiddleware,error
basicAuth := new(BasicRule) func getBasicAuthMiddleware(input interface{}) (BasicRuleMiddleware, error) {
basicAuth := new(BasicRuleMiddleware)
var bytes []byte var bytes []byte
bytes, err := yaml.Marshal(input) bytes, err := yaml.Marshal(input)
if err != nil { if err != nil {
return BasicRule{}, fmt.Errorf("error parsing yaml: %v", err) return BasicRuleMiddleware{}, fmt.Errorf("error parsing yaml: %v", err)
} }
err = yaml.Unmarshal(bytes, basicAuth) err = yaml.Unmarshal(bytes, basicAuth)
if err != nil { if err != nil {
return BasicRule{}, fmt.Errorf("error parsing yaml: %v", err) return BasicRuleMiddleware{}, fmt.Errorf("error parsing yaml: %v", err)
} }
if basicAuth.Username == "" || basicAuth.Password == "" { if basicAuth.Username == "" || basicAuth.Password == "" {
return BasicRule{}, fmt.Errorf("error parsing yaml: empty username/password in %s middleware", basicAuth) return BasicRuleMiddleware{}, fmt.Errorf("error parsing yaml: empty username/password in %s middleware", basicAuth)
} }
return *basicAuth, nil return *basicAuth, nil

View File

@@ -7,7 +7,7 @@ import (
"strings" "strings"
) )
func searchMiddleware(rules []string, middlewares []Middleware) (Middleware, error) { func getMiddleware(rules []string, middlewares []Middleware) (Middleware, error) {
for _, m := range middlewares { for _, m := range middlewares {
if slices.Contains(rules, m.Name) { if slices.Contains(rules, m.Name) {
return m, nil return m, nil
@@ -17,7 +17,24 @@ func searchMiddleware(rules []string, middlewares []Middleware) (Middleware, err
return Middleware{}, errors.New("middleware not found with name: [" + strings.Join(rules, ";") + "]") return Middleware{}, errors.New("middleware not found with name: [" + strings.Join(rules, ";") + "]")
} }
func getMiddleware(rule string, middlewares []Middleware) (Middleware, error) {
type RoutePath struct {
route Route
path string
rules []string
middlewares []Middleware
router *mux.Router
}
func doesExist(tyName string) bool {
middlewareList := []string{BasicAuth, JWTAuth, AccessMiddleware}
if slices.Contains(middlewareList, tyName) {
return true
}
return false
}
func GetMiddleware(rule string, middlewares []Middleware) (Middleware, error) {
for _, m := range middlewares { for _, m := range middlewares {
if strings.Contains(rule, m.Name) { if strings.Contains(rule, m.Name) {
@@ -28,11 +45,3 @@ func getMiddleware(rule string, middlewares []Middleware) (Middleware, error) {
return Middleware{}, errors.New("no middleware found with name " + rule) return Middleware{}, errors.New("no middleware found with name " + rule)
} }
type RoutePath struct {
route Route
path string
rules []string
middlewares []Middleware
router *mux.Router
}

View File

@@ -25,12 +25,12 @@ import (
"time" "time"
) )
// BlocklistMiddleware checks if the request path is forbidden and returns 403 Forbidden // AccessMiddleware checks if the request path is forbidden and returns 403 Forbidden
func (blockList BlockListMiddleware) BlocklistMiddleware(next http.Handler) http.Handler { func (blockList AccessListMiddleware) AccessMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
for _, block := range blockList.List { for _, block := range blockList.List {
if isPathBlocked(r.URL.Path, util.ParseURLPath(blockList.Path+block)) { if isPathBlocked(r.URL.Path, util.ParseURLPath(blockList.Path+block)) {
logger.Warn("%s: access to %s is forbidden", getRealIP(r), r.URL.Path) logger.Debug("%s: %s access forbidden", getRealIP(r), r.URL.Path)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
err := json.NewEncoder(w).Encode(ProxyResponseError{ err := json.NewEncoder(w).Encode(ProxyResponseError{

View File

@@ -50,6 +50,7 @@ func NewRateLimiterWindow(requests int, window time.Duration) *RateLimiter {
} }
} }
// TokenRateLimiter stores tokenRate limit
type TokenRateLimiter struct { type TokenRateLimiter struct {
tokens int tokens int
maxTokens int maxTokens int
@@ -65,7 +66,7 @@ type ProxyResponseError struct {
Message string `json:"message"` Message string `json:"message"`
} }
// JwtAuth Define struct // JwtAuth stores JWT configuration
type JwtAuth struct { type JwtAuth struct {
AuthURL string AuthURL string
RequiredHeaders []string RequiredHeaders []string
@@ -80,13 +81,13 @@ type AuthenticationMiddleware struct {
Headers map[string]string Headers map[string]string
Params map[string]string Params map[string]string
} }
type BlockListMiddleware struct { type AccessListMiddleware struct {
Path string Path string
Destination string Destination string
List []string List []string
} }
// AuthBasic Define Basic auth // AuthBasic contains Basic auth configuration
type AuthBasic struct { type AuthBasic struct {
Username string Username string
Password string Password string
@@ -161,7 +162,7 @@ func (jwtAuth JwtAuth) AuthMiddleware(next http.Handler) http.Handler {
client := &http.Client{} client := &http.Client{}
authResp, err := client.Do(authReq) authResp, err := client.Do(authReq)
if err != nil || authResp.StatusCode != http.StatusOK { if err != nil || authResp.StatusCode != http.StatusOK {
logger.Info("%s %s %s %s", r.Method, r.RemoteAddr, r.URL, r.UserAgent()) logger.Info("%s %s %s %s", r.Method, getRealIP(r), r.URL, r.UserAgent())
logger.Warn("Proxy authentication error") logger.Warn("Proxy authentication error")
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized) w.WriteHeader(http.StatusUnauthorized)

View File

@@ -33,14 +33,27 @@ func TestMiddleware(t *testing.T) {
{ {
Name: "basic-auth", Name: "basic-auth",
Type: "basic", Type: "basic",
Rule: BasicRule{ Paths: []string{"/", "/admin"},
Rule: BasicRuleMiddleware{
Username: "goma", Username: "goma",
Password: "goma", Password: "goma",
}, },
}, { },
Name: MidName, {
Name: "forbidden path acces",
Type: "access",
Paths: []string{"/", "/admin"},
Rule: BasicRuleMiddleware{
Username: "goma",
Password: "goma",
},
},
{
Name: "jwt",
Type: "jwt", Type: "jwt",
Rule: JWTRuler{ Paths: []string{"/", "/admin"},
Rule: JWTRuleMiddleware{
URL: "https://www.googleapis.com/auth/userinfo.email", URL: "https://www.googleapis.com/auth/userinfo.email",
Headers: map[string]string{}, Headers: map[string]string{},
Params: map[string]string{}, Params: map[string]string{},
@@ -61,21 +74,21 @@ func TestMiddleware(t *testing.T) {
func TestReadMiddleware(t *testing.T) { func TestReadMiddleware(t *testing.T) {
TestMiddleware(t) TestMiddleware(t)
middlewares := getMiddlewares(t) middlewares := getMiddlewares(t)
middleware, err := searchMiddleware(rules, middlewares) middleware, err := getMiddleware(rules, middlewares)
if err != nil { if err != nil {
t.Fatalf("Error searching middleware %s", err.Error()) t.Fatalf("Error searching middleware %s", err.Error())
} }
switch middleware.Type { switch middleware.Type {
case "basic": case "basic":
log.Println("Basic auth") log.Println("Basic auth")
basicAuth, err := ToBasicAuth(middleware.Rule) basicAuth, err := getBasicAuthMiddleware(middleware.Rule)
if err != nil { if err != nil {
log.Fatalln("error:", err) log.Fatalln("error:", err)
} }
log.Printf("Username: %s and password: %s\n", basicAuth.Username, basicAuth.Password) log.Printf("Username: %s and password: %s\n", basicAuth.Username, basicAuth.Password)
case "jwt": case "jwt":
log.Println("JWT auth") log.Println("JWT auth")
jwt, err := ToJWTRuler(middleware.Rule) jwt, err := getJWTMiddleware(middleware.Rule)
if err != nil { if err != nil {
log.Fatalln("error:", err) log.Fatalln("error:", err)
} }
@@ -89,7 +102,7 @@ func TestReadMiddleware(t *testing.T) {
func TestFoundMiddleware(t *testing.T) { func TestFoundMiddleware(t *testing.T) {
middlewares := getMiddlewares(t) middlewares := getMiddlewares(t)
middleware, err := searchMiddleware(rules, middlewares) middleware, err := GetMiddleware("jwt", middlewares)
if err != nil { if err != nil {
t.Errorf("Error getting middleware %v", err) t.Errorf("Error getting middleware %v", err)
} }

View File

@@ -42,14 +42,33 @@ func (gatewayServer GatewayServer) Initialize() *mux.Router {
} }
for _, route := range gateway.Routes { for _, route := range gateway.Routes {
if route.Path != "" { if route.Path != "" {
blM := middleware.BlockListMiddleware{
Path: route.Path, // Apply middlewares to route
List: route.Blocklist,
}
// Apply route middlewares
for _, mid := range route.Middlewares { for _, mid := range route.Middlewares {
if mid.Path != "" { if mid != "" {
secureRouter := r.PathPrefix(util.ParseURLPath(route.Path + mid.Path)).Subrouter() // Get Access middleware if it does exist
accessMiddleware, err := getMiddleware([]string{mid}, middlewares)
if err != nil {
logger.Error("Error: %v", err.Error())
} else {
// Apply access middleware
if accessMiddleware.Type == AccessMiddleware {
blM := middleware.AccessListMiddleware{
Path: route.Path,
List: accessMiddleware.Paths,
}
r.Use(blM.AccessMiddleware)
}
}
// Get route authentication middleware if it does exist
rMiddleware, err := getMiddleware([]string{mid}, middlewares)
if err != nil {
//Error: middleware not found
logger.Error("Error: %v", err.Error())
} else {
for _, midPath := range rMiddleware.Paths {
proxyRoute := ProxyRoute{ proxyRoute := ProxyRoute{
path: route.Path, path: route.Path,
rewrite: route.Rewrite, rewrite: route.Rewrite,
@@ -57,14 +76,11 @@ func (gatewayServer GatewayServer) Initialize() *mux.Router {
disableXForward: route.DisableHeaderXForward, disableXForward: route.DisableHeaderXForward,
cors: route.Cors, cors: route.Cors,
} }
rMiddleware, err := searchMiddleware(mid.Rules, middlewares) secureRouter := r.PathPrefix(util.ParseURLPath(route.Path + midPath)).Subrouter()
if err != nil {
logger.Error("Error: %v", err.Error())
} else {
//Check Authentication middleware //Check Authentication middleware
switch rMiddleware.Type { switch rMiddleware.Type {
case "basic": case BasicAuth:
basicAuth, err := ToBasicAuth(rMiddleware.Rule) basicAuth, err := getBasicAuthMiddleware(rMiddleware.Rule)
if err != nil { if err != nil {
logger.Error("Error: %s", err.Error()) logger.Error("Error: %s", err.Error())
} else { } else {
@@ -80,8 +96,8 @@ func (gatewayServer GatewayServer) Initialize() *mux.Router {
secureRouter.PathPrefix("/").Handler(proxyRoute.ProxyHandler()) // Proxy handler secureRouter.PathPrefix("/").Handler(proxyRoute.ProxyHandler()) // Proxy handler
secureRouter.PathPrefix("").Handler(proxyRoute.ProxyHandler()) // Proxy handler secureRouter.PathPrefix("").Handler(proxyRoute.ProxyHandler()) // Proxy handler
} }
case "jwt": case JWTAuth:
jwt, err := ToJWTRuler(rMiddleware.Rule) jwt, err := getJWTMiddleware(rMiddleware.Rule)
if err != nil { if err != nil {
logger.Error("Error: %s", err.Error()) logger.Error("Error: %s", err.Error())
} else { } else {
@@ -102,7 +118,11 @@ func (gatewayServer GatewayServer) Initialize() *mux.Router {
logger.Error("OAuth is not yet implemented") logger.Error("OAuth is not yet implemented")
logger.Info("Auth middleware ignored") logger.Info("Auth middleware ignored")
default: default:
if !doesExist(rMiddleware.Type) {
logger.Error("Unknown middleware type %s", rMiddleware.Type) logger.Error("Unknown middleware type %s", rMiddleware.Type)
}
}
} }
@@ -122,9 +142,6 @@ func (gatewayServer GatewayServer) Initialize() *mux.Router {
router := r.PathPrefix(route.Path).Subrouter() router := r.PathPrefix(route.Path).Subrouter()
// Apply route Cors // Apply route Cors
router.Use(CORSHandler(route.Cors)) router.Use(CORSHandler(route.Cors))
// Add block access middleware to route, if defined
router.Use(blM.BlocklistMiddleware)
//Domain/host based request routing
if route.Host != "" { if route.Host != "" {
router.Host(route.Host).PathPrefix("").Handler(proxyRoute.ProxyHandler()) router.Host(route.Host).PathPrefix("").Handler(proxyRoute.ProxyHandler())
} else { } else {

View File

@@ -1,5 +1,9 @@
package pkg package pkg
const ConfigFile = "/config/goma.yml" const ConfigFile = "/config/goma.yml" // Default configuration file
const accessControlAllowOrigin = "Access-Control-Allow-Origin" const accessControlAllowOrigin = "Access-Control-Allow-Origin" // Cors
const serverName = "Goma" const serverName = "Goma"
const AccessMiddleware = "access" // access middleware
const BasicAuth = "basic" // basic authentication middleware
const JWTAuth = "jwt" // JWT authentication middleware
const OAuth = "OAuth" // OAuth authentication middleware

View File

@@ -30,6 +30,6 @@ func FullVersion() string {
return ver return ver
} }
const MainExample = "Initialize config: init config --output config.yml\n" + const MainExample = "Initialize config: config init --output config.yml\n" +
"Start server: server \n" + "Start server: server \n" +
"Start server with custom config file: server --config config.yml" "Start server with custom config file: server --config config.yml"