forked from gaia-pipeline/gaia
-
Notifications
You must be signed in to change notification settings - Fork 0
/
handler.go
165 lines (140 loc) · 5.48 KB
/
handler.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package handlers
import (
"crypto/rsa"
"errors"
"fmt"
"net/http"
"strings"
"github.com/GeertJohan/go.rice"
jwt "github.com/dgrijalva/jwt-go"
"github.com/gaia-pipeline/gaia"
"github.com/labstack/echo"
"github.com/labstack/echo/middleware"
)
var (
// errNotAuthorized is thrown when user wants to access resource which is protected
errNotAuthorized = errors.New("no or invalid jwt token provided. You are not authorized")
// errPathLength is a validation error during pipeline name input
errPathLength = errors.New("name of pipeline is empty or one of the path elements length exceeds 50 characters")
// errPipelineNotFound is thrown when a pipeline was not found with the given id
errPipelineNotFound = errors.New("pipeline not found with the given id")
// errInvalidPipelineID is thrown when the given pipeline id is not valid
errInvalidPipelineID = errors.New("the given pipeline id is not valid")
// errPipelineRunNotFound is thrown when a pipeline run was not found with the given id
errPipelineRunNotFound = errors.New("pipeline run not found with the given id")
// errLogNotFound is thrown when a job log file was not found
errLogNotFound = errors.New("job log file not found")
// errPipelineDelete is thrown when a pipeline binary could not be deleted
errPipelineDelete = errors.New("pipeline could not be deleted. Perhaps you don't have the right permissions")
// errPipelineRename is thrown when a pipeline binary could not be renamed
errPipelineRename = errors.New("pipeline could not be renamed")
)
// InitHandlers initializes(registers) all handlers
func InitHandlers(e *echo.Echo) error {
// Define prefix
p := "/api/" + gaia.APIVersion + "/"
// --- Register handlers at echo instance ---
// Users
e.POST(p+"login", UserLogin)
e.GET(p+"users", UserGetAll)
e.POST(p+"user/password", UserChangePassword)
e.DELETE(p+"user/:username", UserDelete)
e.POST(p+"user", UserAdd)
// Pipelines
e.POST(p+"pipeline", CreatePipeline)
e.POST(p+"pipeline/gitlsremote", PipelineGitLSRemote)
e.GET(p+"pipeline/created", CreatePipelineGetAll)
e.GET(p+"pipeline/name", PipelineNameAvailable)
e.GET(p+"pipeline", PipelineGetAll)
e.GET(p+"pipeline/:pipelineid", PipelineGet)
e.PUT(p+"pipeline/:pipelineid", PipelineUpdate)
e.DELETE(p+"pipeline/:pipelineid", PipelineDelete)
e.POST(p+"pipeline/:pipelineid/start", PipelineStart)
e.GET(p+"pipeline/latest", PipelineGetAllWithLatestRun)
e.POST(p+"pipeline/githook", GitWebHook)
// PipelineRun
e.POST(p+"pipelinerun/:pipelineid/:runid/stop", PipelineStop)
e.GET(p+"pipelinerun/:pipelineid/:runid", PipelineRunGet)
e.GET(p+"pipelinerun/:pipelineid", PipelineGetAllRuns)
e.GET(p+"pipelinerun/:pipelineid/latest", PipelineGetLatestRun)
e.GET(p+"pipelinerun/:pipelineid/:runid/log", GetJobLogs)
// Secrets
e.GET(p+"secrets", ListSecrets)
e.DELETE(p+"secret/:key", RemoveSecret)
e.POST(p+"secret", SetSecret)
e.PUT(p+"secret/update", SetSecret)
// Middleware
e.Use(middleware.Recover())
//e.Use(middleware.Logger())
e.Use(middleware.BodyLimit("32M"))
e.Use(authBarrier)
// Extra options
e.HideBanner = true
// Are we in production mode?
if !gaia.Cfg.DevMode {
staticAssets, err := rice.FindBox("../frontend/dist")
if err != nil {
gaia.Cfg.Logger.Error("Cannot find assets in production mode.")
return err
}
// Register handler for static assets
assetHandler := http.FileServer(staticAssets.HTTPBox())
e.GET("/", echo.WrapHandler(assetHandler))
e.GET("/favicon.ico", echo.WrapHandler(assetHandler))
e.GET("/assets/css/*", echo.WrapHandler(http.StripPrefix("/", assetHandler)))
e.GET("/assets/js/*", echo.WrapHandler(http.StripPrefix("/", assetHandler)))
e.GET("/assets/css/assets/fonts/*", echo.WrapHandler(http.StripPrefix("/assets/css/", assetHandler)))
e.GET("/assets/img/*", echo.WrapHandler(http.StripPrefix("/", assetHandler)))
}
return nil
}
// authBarrier is the middleware which prevents user exploits.
// It makes sure that the request contains a valid jwt token.
// TODO: Role based access
func authBarrier(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
// Login, WebHook callback and static resources are open
// The webhook callback has it's own authentication method
if strings.Contains(c.Path(), "/login") ||
c.Path() == "/" ||
strings.Contains(c.Path(), "/assets/") ||
c.Path() == "/favicon.ico" ||
strings.Contains(c.Path(), "pipeline/githook") {
return next(c)
}
// Get JWT token
jwtRaw := c.Request().Header.Get("Authorization")
split := strings.Split(jwtRaw, " ")
if len(split) != 2 {
return c.String(http.StatusForbidden, errNotAuthorized.Error())
}
jwtString := split[1]
// Parse token
token, err := jwt.Parse(jwtString, func(token *jwt.Token) (interface{}, error) {
signingMethodError := fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
switch token.Method.(type) {
case *jwt.SigningMethodHMAC:
if _, ok := gaia.Cfg.JWTKey.([]byte); !ok {
return nil, signingMethodError
}
return gaia.Cfg.JWTKey, nil
case *jwt.SigningMethodRSA:
if _, ok := gaia.Cfg.JWTKey.(*rsa.PrivateKey); !ok {
return nil, signingMethodError
}
return gaia.Cfg.JWTKey.(*rsa.PrivateKey).Public(), nil
default:
return nil, signingMethodError
}
})
if err != nil {
return c.String(http.StatusForbidden, err.Error())
}
// Validate token
if _, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
// All ok, continue
return next(c)
}
return c.String(http.StatusForbidden, errNotAuthorized.Error())
}
}