This repository has been archived by the owner on Jan 7, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 175
/
controllers.go
185 lines (160 loc) · 4.68 KB
/
controllers.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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
package authentication
import (
"encoding/json"
"net/http"
jwt "github.com/dgrijalva/jwt-go"
"github.com/gorilla/context"
"github.com/sensu/uchiwa/uchiwa/audit"
"github.com/sensu/uchiwa/uchiwa/helpers"
"github.com/sensu/uchiwa/uchiwa/logger"
"github.com/sensu/uchiwa/uchiwa/structs"
)
// New function initalizes and returns a Config struct
func New(auth structs.Auth) Config {
c := Config{
Auth: auth,
}
return c
}
// publicHandler does not enforce authentication
func publicHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
next.ServeHTTP(w, r)
})
}
// restrictedHandler enforce authentication by validating the JWT
// or the access token provided in the configuration
func restrictedHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var token *jwt.Token
authenticationToken, err := r.Cookie(authenticationCookieName)
if err == nil {
// Verify the JWT
token, err = verifyJWT(authenticationToken.Value)
if err != nil {
logger.Debug("No JWT token provided")
} else {
xsrfTokenFromClaims, ok := token.Claims["xsrfToken"]
if !ok {
logger.Debug("The XSRF Token is missing from the JWT claims")
http.Error(w, "Request unauthorized", http.StatusUnauthorized)
return
}
xsrfTokenFromHeader := r.Header.Get("X-XSRF-TOKEN")
if xsrfTokenFromHeader == "" || xsrfTokenFromClaims != xsrfTokenFromHeader {
logger.Debug("The XSRF token does not match the XSRF claim")
http.Error(w, "Request unauthorized", http.StatusUnauthorized)
return
}
}
} else {
logger.Debugf("No AuthenticationToken cookie found: %s", err.Error())
}
// Verify the access token if no JWT was provided
if err != nil {
token, err = verifyAccessToken(r)
}
// If no JWT or access token found
if err != nil {
logger.Debug("No access token provided")
http.Error(w, "Request unauthorized", http.StatusUnauthorized)
return
}
// Determine the audit level of the request
var level string
if r.Method == "GET" || r.Method == "HEAD" {
level = "verbose"
} else {
level = "default"
}
// Determine the user of the request
var username string
username, ok := token.Claims["username"].(string)
if !ok {
username = "Unknown"
}
// Add the request to the audit log
log := structs.AuditLog{
Action: r.Method,
Level: level,
RemoteAddr: helpers.GetIP(r),
URL: r.URL.String(),
User: username,
}
audit.Log(log)
setJWTInContext(r, token)
next.ServeHTTP(w, r)
context.Clear(r)
return
})
}
// Authenticate calls the proper handler based on whether authentication is enabled or not
func (c *Config) Authenticate(next http.Handler) http.Handler {
if c.DriverName == "none" {
return publicHandler(next)
}
return restrictedHandler(next)
}
// Login authenticates a user against the authentication driver
func (c *Config) Login() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
decoder := json.NewDecoder(r.Body)
var data interface{}
err := decoder.Decode(&data)
if err != nil {
logger.Warningf("Could not decode the body: %s", err)
http.Error(w, "", http.StatusInternalServerError)
return
}
m, ok := data.(map[string]interface{})
if !ok {
logger.Warningf("Could not assert the body: %s", err)
http.Error(w, "", http.StatusInternalServerError)
return
}
u := m["user"].(string)
p := m["pass"].(string)
if u == "" || p == "" {
logger.Info("Authentication failed: user and password must not be empty")
http.Error(w, "", http.StatusUnauthorized)
return
}
user, err := c.login(u, p)
if err != nil {
logger.Info(err)
// Add the login failure to the audit log
log := structs.AuditLog{
Action: "loginfailure",
Level: "default",
Output: err.Error(),
RemoteAddr: helpers.GetIP(r),
User: u,
}
audit.Log(log)
http.Error(w, "", http.StatusUnauthorized)
return
}
xsrfToken := helpers.RandomString(32)
authenticationToken, err := GetToken(user, xsrfToken)
if err != nil {
logger.Infof("Authentication failed, could not create the token: %s", err)
http.Error(w, "", http.StatusUnauthorized)
return
}
// Set the required cookies
SetCookies(w, r, authenticationToken, xsrfToken)
// Add the successful login to the audit log
log := structs.AuditLog{
Action: "loginsuccess",
Level: "default",
RemoteAddr: helpers.GetIP(r),
User: u,
}
audit.Log(log)
return
}
http.Redirect(w, r, "/#/login", http.StatusFound)
return
})
}