// loginOk checks that the user is logged in and authorized. // If not, it performs one step of the oauth process. func (h *Handler) loginOk(ctx context.Context, w http.ResponseWriter, r *http.Request) (context.Context, bool) { var user sess err := session.Get(r, &user, h.sessionConfig()) if err != nil && err != http.ErrNoCookie { h.deleteCookie(w) http.Error(w, "internal error", 500) return ctx, false } redirectURL := "https://" + r.Host + callbackPath conf := &oauth2.Config{ ClientID: h.ClientID, ClientSecret: h.ClientSecret, RedirectURL: redirectURL, Scopes: h.Scopes, Endpoint: github.Endpoint, } if conf.Scopes == nil { conf.Scopes = []string{"user:email", "read:org"} } if user.OAuthToken != nil { session.Set(w, user, h.sessionConfig()) // refresh the cookie ctx = context.WithValue(ctx, sessionKey, &Session{ Client: conf.Client(ctx, user.OAuthToken), }) return ctx, true } if r.URL.Path == callbackPath { if r.FormValue("state") != user.State { h.deleteCookie(w) http.Error(w, "access forbidden", 401) return ctx, false } tok, err := conf.Exchange(ctx, r.FormValue("code")) if err != nil { h.deleteCookie(w) http.Error(w, "access forbidden", 401) return ctx, false } client := conf.Client(ctx, tok) if h.RequireOrg != "" { resp, err := client.Get("https://api.github.com/user/memberships/orgs/" + h.RequireOrg) if err != nil || resp.StatusCode != 200 { h.deleteCookie(w) http.Error(w, "access forbidden", 401) return ctx, false } var v struct { State string User struct { Login string } } if err := json.NewDecoder(resp.Body).Decode(&v); err != nil { log.Println("Decode:", err) h.deleteCookie(w) http.Error(w, "Internal Server Error - Invalid JSON from Github", 500) return ctx, false } log.Println("State:", v.User.Login, v.State) if v.State != "active" { log.Println("User not active but:", v.State) h.deleteCookie(w) http.Error(w, "Access Forbidden - You're not in the Github org.", 401) return ctx, false } } session.Set(w, sess{OAuthToken: tok}, h.sessionConfig()) http.Redirect(w, r, user.NextURL, http.StatusTemporaryRedirect) return ctx, false } u := *r.URL u.Scheme = "https" u.Host = r.Host state := newState() session.Set(w, sess{NextURL: u.String(), State: state}, h.sessionConfig()) http.Redirect(w, r, conf.AuthCodeURL(state), http.StatusTemporaryRedirect) return ctx, false }
func (h *Handler) deleteCookie(w http.ResponseWriter) error { conf := h.sessionConfig() conf.MaxAge = -1 * time.Second return session.Set(w, sess{}, conf) }