URI OAuth2::getVerifyURL(const URI &uri, const string &state) const { // Check that SID matches state (Confirm anti-forgery state token) if (!uri.has("code") || !uri.has("state") || uri.get("state") != state) { LOG_DEBUG(3, "Failed anti-forgery check: uri code=" << (uri.has("code") ? uri.get("code") : "<null>") << " uri state=" << (uri.has("state") ? uri.get("state") : "<null>") << " server state=" << state); THROWC("Failed anti-forgery check", Event::HTTPStatus::HTTP_UNAUTHORIZED); } // Check config validateOption(clientID, "client-id"); validateOption(clientSecret, "client-secret"); validateOption(redirectBase, "redirect-base"); validateOption(tokenURL, "token-url"); // Exchange code for access token and ID token URI postURI(tokenURL); // Setup Query data postURI.set("code", uri.get("code")); postURI.set("client_id", clientID); postURI.set("client_secret", clientSecret); postURI.set("redirect_uri", redirectBase + uri.getPath()); postURI.set("grant_type", "authorization_code"); LOG_DEBUG(5, __func__ << ": " << postURI); return postURI; }
bool JSONAPI::handlePage(HTTP::WebContext &ctx, ostream &stream, const URI &uri) { if (!String::startsWith(uri.getPath(), root)) return false; string cmd = uri.getPath().substr(root.length()); // Look up command api_t::const_iterator it = api.find(cmd); if (it == api.end()) return false; ctx.setDynamic(); // Don't cache HTTP::Connection &con = ctx.getConnection(); bool jsonp = !jsonpCB.empty() && uri.has(jsonpCB); if (jsonp) { con.getResponse().setContentType("application/javascript"); con << uri.get(jsonpCB) << '('; } else con.getResponse().setContentType("application/json"); JSON::Writer writer(con, 0, !uri.has("pretty"), uri.has("python_mode") ? JSON::Writer::PYTHON_MODE : JSON::Writer::JSON_MODE); try { // Parse JSON data JSON::ValuePtr msg; if (con.getRequest().hasContentType() && String::startsWith(con.getRequest().getContentType(), "application/json")) { MemoryBuffer &payload = con.getPayload(); if (payload.getFill()) msg = JSON::Reader(payload).parse(); } else if (!uri.empty()) { msg = new JSON::Dict; for (URI::const_iterator it = uri.begin(); it != uri.end(); it++) msg->insert(it->first, it->second); } // Dispatch API command if (msg.isNull()) LOG_DEBUG(5, "JSONAPI Call: " << cmd << "()"); else LOG_DEBUG(5, "JSONAPI Call: " << cmd << '(' << *msg << ')'); it->second->handle(ctx, cmd, msg, writer); // Make sure JSON stream is complete writer.close(); } catch (const Exception &e) { LOG_ERROR(e); // Clear possibly partial or invalid response con.clearResponseBuffer(); // jsonp header if (jsonp) con << uri.get(jsonpCB) << '('; // Send error message JSON::Writer writer(con, 0, true); writer.beginList(); writer.append("error"); writer.append(e.getMessage()); writer.endList(); writer.close(); } if (jsonp) con << ");"; return true; }
bool OAuth2SessionLogin::handlePage(HTTP::WebContext &ctx, ostream &stream, const URI &uri) { HTTP::Connection &con = ctx.getConnection(); HTTP::Request &request = con.getRequest(); HTTP::Response &response = con.getResponse(); ctx.setDynamic(); // Don't cache // Force secure if (!con.isSecure()) THROWCS("Cannot logon via insecure port", HTTP::StatusCode::HTTP_UNAUTHORIZED); // Get session ID string sid = request.findCookie(sessionManager->getSessionCookie()); if (sid.empty() && uri.has("state")) sid = uri.get("state"); HTTP::SessionPtr session = sessionManager->findSession(ctx, sid); try { if (session.isNull() || (uri.has("state") && uri.get("state") != session->getID()) || (!uri.has("state") && session->getUser().empty())) { session = sessionManager->openSession(ctx); sid = session->getID(); URI redirectURL = auth->getRedirectURL(uri.getPath(), sid); response.redirect(redirectURL); } else if (session->getUser().empty()) { // TODO Make sure session is not very old URI postURI = auth->getVerifyURL(uri, sid); LOG_DEBUG(5, "Token URI: " << postURI); // Extract query data string data = postURI.getQuery(); postURI.setQuery(""); // Verify authorization with OAuth2 server HTTP::Transaction tran(sslCtx); tran.post(postURI, data.data(), data.length(), "application/x-www-form-urlencoded", 1.0); // Read response tran.receiveHeader(); JSON::ValuePtr token = JSON::Reader(tran).parse(); LOG_DEBUG(5, "Token Response: \n" << tran.getResponse() << *token); // Verify token string accessToken = auth->verifyToken(token); // Get profile URI profileURL = auth->getProfileURL(accessToken); HTTP::Transaction tran2(sslCtx); tran2.get(profileURL); // Read response tran2.receiveHeader(); JSON::ValuePtr profile = JSON::Reader(tran2).parse(); // Process profile string email = profile->getString("email"); if (!profile->getBoolean("email_verified")) THROWCS("Email not verified", HTTP::StatusCode::HTTP_UNAUTHORIZED); session->setUser(email); LOG_INFO(1, "Authorized: " << email); // Final redirect to remove auth parameters response.redirect(uri.getPath()); } else return false; // Already authorized // Make sure session cookie is set sessionManager->setSessionCookie(ctx); } catch (...) { // Close session on error if (!sid.empty()) sessionManager->closeSession(ctx, sid); throw; } return true; }