auth
2014-08-16
Parent:51700827b6ee
auth/session.go
Redirect unauthenticated users to the login page. Redirect unauthenticated users to the login page, and encode the current URL in the redirect_to param so that the user returns to the OAuth2 flow after they log in.
| paddy@6 | 1 package auth |
| paddy@1 | 2 |
| paddy@19 | 3 import ( |
| paddy@19 | 4 "errors" |
| paddy@19 | 5 "net/http" |
| paddy@21 | 6 "net/url" |
| paddy@19 | 7 "time" |
| paddy@19 | 8 |
| paddy@21 | 9 "strings" |
| paddy@19 | 10 "secondbit.org/uuid" |
| paddy@19 | 11 ) |
| paddy@19 | 12 |
| paddy@19 | 13 const sessionCookie = "session" |
| paddy@19 | 14 |
| paddy@19 | 15 var ( |
| paddy@19 | 16 ErrSessionNotFound = errors.New("Session not found.") |
| paddy@19 | 17 ) |
| paddy@19 | 18 |
| paddy@19 | 19 type Session struct { |
| paddy@19 | 20 Token string |
| paddy@19 | 21 User uuid.ID |
| paddy@19 | 22 Expires time.Time |
| paddy@19 | 23 Created time.Time |
| paddy@19 | 24 IP string |
| paddy@19 | 25 } |
| paddy@1 | 26 |
| paddy@2 | 27 func validateSession(r *http.Request, c Context) error { |
| paddy@19 | 28 cookie, err := r.Cookie(sessionCookie) |
| paddy@19 | 29 if err == http.ErrNoCookie { |
| paddy@19 | 30 return ErrSessionNotFound |
| paddy@19 | 31 } |
| paddy@19 | 32 _, err = c.Sessions.GetSession(cookie.Value) |
| paddy@19 | 33 return err |
| paddy@1 | 34 } |
| paddy@19 | 35 |
| paddy@19 | 36 func HandleLoginRequest(w http.ResponseWriter, r *http.Request, ctx Context) { |
| paddy@19 | 37 if r.Method == "GET" { |
| paddy@19 | 38 ctx.RenderLogin(w, r) |
| paddy@19 | 39 return |
| paddy@19 | 40 } else if r.Method != "POST" { |
| paddy@19 | 41 // TODO: return bad method error |
| paddy@19 | 42 return |
| paddy@19 | 43 } |
| paddy@19 | 44 |
| paddy@19 | 45 if r.FormValue("username") == "" || r.FormValue("password") == "" { |
| paddy@19 | 46 // TODO: return unauthenticated error |
| paddy@19 | 47 return |
| paddy@19 | 48 } |
| paddy@19 | 49 id, err := ctx.Profiles.GetProfile(r.FormValue("username"), r.FormValue("password")) |
| paddy@19 | 50 if err != nil { |
| paddy@19 | 51 if err == ErrProfileNotFound { |
| paddy@19 | 52 // TODO: return unauthenticated error |
| paddy@19 | 53 return |
| paddy@19 | 54 } |
| paddy@19 | 55 // TODO: return internal server error |
| paddy@19 | 56 return |
| paddy@19 | 57 } |
| paddy@19 | 58 session := Session{ |
| paddy@19 | 59 Token: newToken(), |
| paddy@19 | 60 User: id, |
| paddy@19 | 61 Expires: time.Now().Add(ctx.Config.SessionLength), |
| paddy@19 | 62 Created: time.Now(), |
| paddy@19 | 63 IP: r.Header.Get(ctx.Config.RequestIPHeader), |
| paddy@19 | 64 } |
| paddy@19 | 65 err = ctx.Sessions.SetSession(session) |
| paddy@19 | 66 if err != nil { |
| paddy@19 | 67 // TODO: return internal server error |
| paddy@19 | 68 return |
| paddy@19 | 69 } |
| paddy@19 | 70 http.SetCookie(w, &http.Cookie{ |
| paddy@19 | 71 Name: sessionCookie, |
| paddy@19 | 72 Value: session.Token, |
| paddy@19 | 73 Expires: session.Expires, |
| paddy@19 | 74 Secure: true, |
| paddy@19 | 75 HttpOnly: true, |
| paddy@19 | 76 }) |
| paddy@21 | 77 |
| paddy@21 | 78 redirectString := r.URL.Query().Get("redirect_to") |
| paddy@21 | 79 if redirectString != "" { |
| paddy@21 | 80 redirectURI, err := url.Parse(redirectString) |
| paddy@21 | 81 if err != nil { |
| paddy@21 | 82 // TODO: render a bad request error |
| paddy@21 | 83 return |
| paddy@21 | 84 } |
| paddy@21 | 85 if !strings.HasSuffix("."+ctx.Config.LoginRedirectDomain, redirectURI.Host) && redirectURI.Host != ctx.Config.LoginRedirectDomain { |
| paddy@21 | 86 // TODO: render a bad request error |
| paddy@21 | 87 return |
| paddy@21 | 88 } |
| paddy@21 | 89 } else { |
| paddy@21 | 90 redirectString = "https://" + ctx.Config.LoginRedirectDomain |
| paddy@21 | 91 } |
| paddy@21 | 92 http.Redirect(w, r, redirectString, http.StatusFound) |
| paddy@21 | 93 return |
| paddy@19 | 94 } |