Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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;
}