git.iko.soy/typeable/oauth2-proxy
on master help sign in
don't promote htpasswd auth; auth directly
4367e47Jehiah Czebotar
oauthproxy.go+56−16
@@ -150,7 +150,7 @@ func (p *OauthProxy) getUserInfo(token string) (string, error) {
150
150
151func (p *OauthProxy) ClearCookie(rw http.ResponseWriter, req *http.Request) {
151func (p *OauthProxy) ClearCookie(rw http.ResponseWriter, req *http.Request) {
152 domain := strings.Split(req.Host, ":")[0]
152 domain := strings.Split(req.Host, ":")[0]
153− if *cookieDomain != "" {
153+ if *cookieDomain != "" && strings.HasSuffix(domain, *cookieDomain) {
154 domain = *cookieDomain
154 domain = *cookieDomain
155 }
155 }
156 cookie := &http.Cookie{
156 cookie := &http.Cookie{
@@ -165,9 +165,9 @@ func (p *OauthProxy) ClearCookie(rw http.ResponseWriter, req *http.Request) {
165}
165}
166
166
167func (p *OauthProxy) SetCookie(rw http.ResponseWriter, req *http.Request, val string) {
167func (p *OauthProxy) SetCookie(rw http.ResponseWriter, req *http.Request, val string) {
168−
168+
169 domain := strings.Split(req.Host, ":")[0] // strip the port (if any)
169 domain := strings.Split(req.Host, ":")[0] // strip the port (if any)
170− if *cookieDomain != "" {
170+ if *cookieDomain != "" && strings.HasSuffix(domain, *cookieDomain) {
171 domain = *cookieDomain
171 domain = *cookieDomain
172 }
172 }
173 cookie := &http.Cookie{
173 cookie := &http.Cookie{
@@ -182,7 +182,6 @@ func (p *OauthProxy) SetCookie(rw http.ResponseWriter, req *http.Request, val st
182 http.SetCookie(rw, cookie)
182 http.SetCookie(rw, cookie)
183}
183}
184
184
185−
186func (p *OauthProxy) ErrorPage(rw http.ResponseWriter, code int, title string, message string) {
185func (p *OauthProxy) ErrorPage(rw http.ResponseWriter, code int, title string, message string) {
187 log.Printf("ErrorPage %d %s %s", code, title, message)
186 log.Printf("ErrorPage %d %s %s", code, title, message)
188 rw.WriteHeader(code)
187 rw.WriteHeader(code)
@@ -202,14 +201,52 @@ func (p *OauthProxy) SignInPage(rw http.ResponseWriter, req *http.Request, code
202 p.ClearCookie(rw, req)
201 p.ClearCookie(rw, req)
203 rw.WriteHeader(code)
202 rw.WriteHeader(code)
204 templates := getTemplates()
203 templates := getTemplates()
204+
205+ t := struct{
206+ SignInMessage string
207+ Htpasswd bool
208+ }{
205− t := struct{ SignInMessage string }{SignInMessage: p.SignInMessage}
209+ SignInMessage: p.SignInMessage,
210+ Htpasswd: p.HtpasswdFile != nil,
211+ }
206 templates.ExecuteTemplate(rw, "sign_in.html", t)
212 templates.ExecuteTemplate(rw, "sign_in.html", t)
207}
213}
208
214
215+func (p *OauthProxy) ManualSignIn(rw http.ResponseWriter, req *http.Request) (string, bool){
216+ if req.Method != "POST" || p.HtpasswdFile == nil{
217+ return "", false
218+ }
219+ user := req.FormValue("username")
220+ passwd := req.FormValue("password")
221+ if user == "" {
222+ return "", false
223+ }
224+ // check auth
225+ if p.HtpasswdFile.Validate(user, passwd) {
226+ log.Printf("authenticated %s via manual sign in", user)
227+ return user, true
228+ }
229+ return "", false
230+}
231+
209func (p *OauthProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
232func (p *OauthProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
210 // check if this is a redirect back at the end of oauth
233 // check if this is a redirect back at the end of oauth
234+ remoteIP := req.Header.Get("X-Real-IP")
235+ if remoteIP == "" {
236+ remoteIP = req.RemoteAddr
237+ }
238+ log.Printf("%s %s %s", remoteIP, req.Method, req.URL.Path)
239+
240+ var ok bool
241+ var user string
211 if req.URL.Path == signInPath {
242 if req.URL.Path == signInPath {
243+ user, ok = p.ManualSignIn(rw, req)
244+ if ok {
245+ p.SetCookie(rw, req, user)
246+ http.Redirect(rw, req, "/", 302)
247+ } else {
212− p.SignInPage(rw, req, 200)
248+ p.SignInPage(rw, req, 200)
249+ }
213 return
250 return
214 }
251 }
215 if req.URL.Path == oauthStartPath {
252 if req.URL.Path == oauthStartPath {
@@ -260,20 +297,22 @@ func (p *OauthProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
260 }
297 }
261 }
298 }
262
299
300+ if !ok {
263− cookie, err := req.Cookie(p.CookieKey)
301+ cookie, err := req.Cookie(p.CookieKey)
264− var ok bool
265− var email string
266− var user string
267− if err == nil {
302+ if err == nil {
303+ var email string
268− email, ok = validateCookie(cookie, p.CookieSeed)
304+ email, ok = validateCookie(cookie, p.CookieSeed)
269− user = strings.Split(email, "@")[0]
305+ user = strings.Split(email, "@")[0]
306+ }
270 }
307 }
271
308
272 if !ok {
309 if !ok {
273 user, ok = p.CheckBasicAuth(req)
310 user, ok = p.CheckBasicAuth(req)
311+ // if we want to promote basic auth requests to cookie'd requests, we could do that here
312+ // not sure that would be ideal in all circumstances though
274− if ok {
313+ // if ok {
275− p.SetCookie(rw, req, user)
314+ // p.SetCookie(rw, req, user)
276− }
315+ // }
277 }
316 }
278
317
279 if !ok {
318 if !ok {
@@ -308,6 +347,7 @@ func (p *OauthProxy) CheckBasicAuth(req *http.Request) (string, bool) {
308 return "", false
347 return "", false
309 }
348 }
310 if p.HtpasswdFile.Validate(pair[0], pair[1]) {
349 if p.HtpasswdFile.Validate(pair[0], pair[1]) {
350+ log.Printf("authenticated %s via basic auth", pair[0])
311 return pair[0], true
351 return pair[0], true
312 }
352 }
313 return "", false
353 return "", false
templates.go+18−4
@@ -7,20 +7,34 @@ import (
7
7
8func getTemplates() *template.Template {
8func getTemplates() *template.Template {
9 t, err := template.New("foo").Parse(`{{define "sign_in.html"}}
9 t, err := template.New("foo").Parse(`{{define "sign_in.html"}}
10+<!DOCTYPE html>
11+<html lang="en" charset="utf-8">
10−<html><head><title>Sign In</title></head>
12+<head><title>Sign In</title></head>
11− <body>
13+<body>
12 <form method="GET" action="/oauth2/start">
14 <form method="GET" action="/oauth2/start">
13 <button type="submit">Sign In w/ Google</button>
15 <button type="submit">Sign In w/ Google</button>
14 {{.SignInMessage}}
16 {{.SignInMessage}}
15 </form>
17 </form>
18+ {{ if .Htpasswd }}
19+ <fieldset>
20+ <form method="POST" action="/oauth2/sign_in">
21+ <label>Username: <input type="text" name="username" size="10"></label><br/>
22+ <label>Password: <input type="password" name="password" size="10"></label><br/>
23+ <button type="submit">Sign In</button>
24+ </form>
25+ </fieldset>
26+ {{ end }}
16−</body></html>
27+</body>
28+</html>
17{{end}}`)
29{{end}}`)
18 if err != nil {
30 if err != nil {
19 log.Fatalf("failed parsing template %s", err.Error())
31 log.Fatalf("failed parsing template %s", err.Error())
20 }
32 }
21
33
22 t, err = t.Parse(`{{define "error.html"}}
34 t, err = t.Parse(`{{define "error.html"}}
35+<!DOCTYPE html>
36+<html lang="en" charset="utf-8">
23−<html><head><title>{{.Title}}</title></head>
37+<head><title>{{.Title}}</title></head>
24<body>
38<body>
25 <h2>{{.Title}}</h2>
39 <h2>{{.Title}}</h2>
26 <p>{{.Message}}</p>
40 <p>{{.Message}}</p>