func (h *Handler) AuthorizeHandler(w http.ResponseWriter, r *http.Request) { resp := h.server.NewResponse() defer resp.Close() if ar := h.server.HandleAuthorizeRequest(resp, r); ar != nil { // For now, a provider must be given. // TODO there should be a fallback provider which is a redirect to the login endpoint. This should be configurable by env var. // Let's see if this is a valid provider. If not, return an error. provider, err := h.Providers.Find(r.URL.Query().Get("provider")) if err != nil { http.Error(w, fmt.Sprintf(`Provider "%s" not known.`, err), http.StatusBadRequest) return } // This could be made configurable with `connection.GetCodeKeyName()` code := r.URL.Query().Get("access_code") if code == "" { // If no code was given we have to initiate the provider's authorization workflow url := provider.GetAuthCodeURL(ar) http.Redirect(w, r, url, http.StatusFound) return } // Create a session by exchanging the code for the auth code connection, err := provider.Exchange(code) if err != nil { http.Error(w, fmt.Sprintf("Could not exchange access code: %s", err), http.StatusUnauthorized) return } subject := connection.GetRemoteSubject() user, err := h.Connections.FindByRemoteSubject(provider.GetID(), subject) if err == account.ErrNotFound { // The subject is not linked to any account. http.Error(w, "Provided token is not linked to any existing account.", http.StatusUnauthorized) return } else if err != nil { // Something else went wrong http.Error(w, fmt.Sprintf("Could assert subject claim: %s", err), http.StatusInternalServerError) return } ar.UserData = jwt.NewClaimsCarrier(uuid.New(), user.GetLocalSubject(), h.Issuer, h.Audience, time.Now(), time.Now()) ar.Authorized = true h.server.FinishAuthorizeRequest(resp, r, ar) } if resp.IsError { resp.StatusCode = http.StatusUnauthorized } osin.OutputJSON(resp, w, r) }
func (h *Handler) AuthorizeHandler(w http.ResponseWriter, r *http.Request) { r.ParseForm() resp := h.server.NewResponse() defer resp.Close() code := r.Form.Get("code") state := r.Form.Get("state") if code != "" { if stateData, err := h.States.GetStateData(state); err != nil { // Something else went wrong http.Error(w, fmt.Sprintf("Could not persist state data: %s", err), http.StatusInternalServerError) return } else { r.Form = stateData.ToURLValues() } } if ar := h.server.HandleAuthorizeRequest(resp, r); ar != nil { // For now, a provider must be given. // TODO there should be a fallback provider which is a redirect to the login endpoint. This should be configurable by env var. // Let's see if this is a valid provider. If not, return an error. providerName := r.Form.Get("provider") if r.Form.Get("provider") == "" && h.SignInLocation != "" { providerName = "login" } provider, err := h.Providers.Find(providerName) if err != nil { http.Error(w, fmt.Sprintf(`Provider "%s" not known and no sign in location provided.`, providerName), http.StatusBadRequest) return } if code == "" { stateData := new(storage.StateData) if err := stateData.FromAuthorizeRequest(ar, provider.GetID()); err != nil { // Something else went wrong http.Error(w, fmt.Sprintf("Could not hydrate state data: %s", err), http.StatusInternalServerError) return } stateData.ExpireInOneHour() if err := h.States.SaveStateData(stateData); err != nil { // Something else went wrong http.Error(w, fmt.Sprintf("Could not persist state data: %s", err), http.StatusInternalServerError) return } // If no code was given we have to initiate the provider's authorization workflow url := provider.GetAuthCodeURL(stateData.ID) http.Redirect(w, r, url, http.StatusFound) return } // Create a session by exchanging the code for the auth code session, err := provider.Exchange(code) if err != nil { http.Error(w, fmt.Sprintf("Could not exchange access code: %s", err), http.StatusUnauthorized) return } var conn connection.Connection var acc account.Account if session.GetForcedLocalSubject() != "" { acc, err = h.Accounts.Get(session.GetForcedLocalSubject()) } else { conn, err = h.Connections.FindByRemoteSubject(provider.GetID(), session.GetRemoteSubject()) } if err == pkg.ErrNotFound { // The subject is not linked to any account. if h.SignUpLocation == "" { http.Error(w, "No sign up location is set. Please contact your admin.", http.StatusInternalServerError) return } redirect, err := url.Parse(h.SignUpLocation) if err != nil { http.Error(w, fmt.Sprintf("Could not parse redirect URL: %s", err), http.StatusInternalServerError) return } query := redirect.Query() query.Add("redirect_uri", pkg.JoinURL(h.HostURL, "oauth2/authorize")) query.Add("access_token", session.GetToken().AccessToken) query.Add("refresh_token", session.GetToken().RefreshToken) query.Add("token_type", session.GetToken().TokenType) query.Add("provider", provider.GetID()) query.Add("remote_subject", session.GetRemoteSubject()) redirect.RawQuery = query.Encode() log.WithFields(log.Fields{ "provider": provider.GetID(), "subject": session.GetRemoteSubject(), "redirect": h.SignUpLocation, }).Warnf(`Remote subject is not linked to any local subject. Redirecting to sign up page.`) http.Redirect(w, r, redirect.String(), http.StatusFound) return } else if err != nil { // Something else went wrong http.Error(w, fmt.Sprintf("Could not assert subject claim: %s", err), http.StatusInternalServerError) return } var localSubject string if conn != nil { localSubject = conn.GetLocalSubject() } else if acc != nil { localSubject = acc.GetID() } ar.UserData = jwt.NewClaimsCarrier(uuid.New(), h.Issuer, localSubject, ar.Client.GetId(), time.Now().Add(time.Duration(ar.Expiration)*time.Second), time.Now(), time.Now()) ar.Authorized = true h.server.FinishAuthorizeRequest(resp, r, ar) } if resp.IsError { resp.StatusCode = http.StatusUnauthorized } osin.OutputJSON(resp, w, r) }