Changeset - 8df5cd7d1b47
[Not reviewed]
0 8 0
Jan Kaluza - 10 years ago 2016-01-07 18:32:17
jkaluza@redhat.com
Spectrum2 manager server: Allow registration of users
8 files changed with 68 insertions and 22 deletions:
0 comments (0 inline, 0 general)
include/transport/Frontend.h
Show inline comments
 
@@ -84,24 +84,25 @@ class Frontend {
 

	
 
		virtual RosterManager *createRosterManager(User *user, Component *component) = 0;
 

	
 
		virtual User *createUser(const Swift::JID &jid, UserInfo &userInfo, Component *component, UserManager *userManager) = 0;
 

	
 
		virtual UserManager *createUserManager(Component *component, UserRegistry *userRegistry, StorageBackend *storageBackend = NULL) = 0;
 

	
 
		virtual void clearRoomList() = 0;
 
		virtual void addRoomToRoomList(const std::string &handle, const std::string &name) = 0;
 

	
 
		virtual std::string setOAuth2Code(const std::string &code, const std::string &state) { return "OAuth2 code is not needed for this frontend."; }
 
		virtual std::string getOAuth2URL(const std::vector<std::string> &args) { return ""; }
 
		virtual std::string getRegistrationFields() { return "Jabber ID\n3rd-party network username\n3rd-party network password"; }
 

	
 
		boost::signal<void (User *, const std::string &name, unsigned int id)> onVCardRequired;
 
		boost::signal<void (User *, boost::shared_ptr<Swift::VCard> vcard)> onVCardUpdated;
 
		boost::signal<void (Buddy *, const Swift::RosterItemPayload &item)> onBuddyUpdated;
 
		boost::signal<void (Buddy *)> onBuddyRemoved;
 
		boost::signal<void (Buddy *, const Swift::RosterItemPayload &item)> onBuddyAdded;
 
		boost::signal<void (Swift::Message::ref message)> onMessageReceived;
 
		boost::signal<void (bool /* isAvailable */)> onAvailableChanged;
 
		boost::signal<void (boost::shared_ptr<Swift::Presence>) > onPresenceReceived;
 
		boost::signal<void (const Swift::JID& jid, boost::shared_ptr<Swift::DiscoInfo> info)> onCapabilitiesReceived;
 
};
 

	
include/transport/UserRegistration.h
Show inline comments
 
@@ -41,25 +41,25 @@ class UserRegistration {
 
		/// Creates new UserRegistration handler.
 
		/// \param component Component associated with this class
 
		/// \param userManager UserManager associated with this class
 
		/// \param storageBackend StorageBackend where the registered users will be stored
 
		UserRegistration(Component *component, UserManager *userManager, StorageBackend *storageBackend);
 

	
 
		/// Destroys UserRegistration.
 
		virtual ~UserRegistration();
 

	
 
		/// Registers new user. This function stores user into database and subscribe user to transport.
 
		/// \param userInfo UserInfo struct with informations about registered user
 
		/// \return false if user is already registered
 
		bool registerUser(const UserInfo &userInfo);
 
		bool registerUser(const UserInfo &userInfo, bool allowPasswordChange = false);
 

	
 
		/// Unregisters user. This function removes all data about user from databa, unsubscribe all buddies
 
		/// managed by this transport and disconnects user if he's connected.
 
		/// \param barejid bare JID of user to unregister
 
		/// \return false if there is no such user registered
 
		bool unregisterUser(const std::string &barejid);
 

	
 
		/// Registers new user. This function stores user into database and subscribe user to transport.
 
		/// \param userInfo UserInfo struct with informations about registered user
 
		/// \return false if user is already registered
 
		virtual bool doUserRegistration(const UserInfo &userInfo) = 0;
 

	
libtransport/AdminInterface.cpp
Show inline comments
 
@@ -316,24 +316,28 @@ void AdminInterface::handleQuery(Swift::Message::ref message) {
 
	else if (message->getBody().find("get_oauth2_url ") == 0) {
 
		std::string body = message->getBody();
 
		std::vector<std::string> args;
 
		boost::split(args, body, boost::is_any_of(" "));
 
		if (args.size() == 3) {
 
			std::string url = m_component->getFrontend()->getOAuth2URL(args);
 
			message->setBody(url);
 
		}
 
		else {
 
			message->setBody("Bad argument count. See 'help'.");
 
		}
 
	}
 
	else if (message->getBody() == "registration_fields") {
 
		std::string fields = m_component->getFrontend()->getRegistrationFields();
 
		message->setBody(fields);
 
	}
 
	else if (message->getBody().find("help") == 0) {
 
		std::string help;
 
		help += "General:\n";
 
		help += "    status - shows instance status\n";
 
		help += "    reload - Reloads config file\n";
 
		help += "    uptime - returns ptime in seconds\n";
 
		help += "Users:\n";
 
		help += "    online_users - returns list of all online users\n";
 
		help += "    online_users_count - number of online users\n";
 
		help += "    online_users_per_backend - shows online users per backends\n";
 
		help += "    has_online_user <bare_JID> - returns 1 if user is online\n";
 
		if (m_userRegistration) {
 
@@ -354,25 +358,25 @@ void AdminInterface::handleQuery(Swift::Message::ref message) {
 
		help += "    shr_memory - Total SHaRed memory spectrum2 backends share together in KB\n";
 
		help += "    used_memory - (res_memory - shr_memory)\n";
 
		help += "    average_memory_per_user - (memory_used_without_any_user - res_memory)\n";
 
		help += "    res_memory_per_backend - RESident memory used by backends in KB\n";
 
		help += "    shr_memory_per_backend - SHaRed memory used by backends in KB\n";
 
		help += "    used_memory_per_backend - (res_memory - shr_memory) per backend\n";
 
		help += "    average_memory_per_user_per_backend - (memory_used_without_any_user - res_memory) per backend\n";
 
		
 
		
 
		message->setBody(help);
 
	}
 
	else {
 
		message->setBody("Unknown command. Try \"help\"");
 
		message->setBody("Unknown command \"" + message->getBody() + "\". Try \"help\"");
 
	}
 
}
 

	
 
void AdminInterface::handleMessageReceived(Swift::Message::ref message) {
 
	if (!message->getTo().getNode().empty())
 
		return;
 

	
 
	std::vector<std::string> const &x = CONFIG_VECTOR(m_component->getConfig(),"service.admin_jid");
 
	if (std::find(x.begin(), x.end(), message->getFrom().toBare().toString()) == x.end()) {
 
	    LOG4CXX_WARN(logger, "Message not from admin user, but from " << message->getFrom().toBare().toString());
 
	    return;
 
	
libtransport/UserRegistration.cpp
Show inline comments
 
@@ -38,31 +38,33 @@ DEFINE_LOGGER(logger, "UserRegistration");
 

	
 
UserRegistration::UserRegistration(Component *component, UserManager *userManager,
 
								   StorageBackend *storageBackend) {
 
	m_component = component;
 
	m_config = m_component->m_config;
 
	m_storageBackend = storageBackend;
 
	m_userManager = userManager;
 
}
 

	
 
UserRegistration::~UserRegistration(){
 
}
 

	
 
bool UserRegistration::registerUser(const UserInfo &row) {
 
bool UserRegistration::registerUser(const UserInfo &row, bool allowPasswordChange) {
 
	UserInfo dummy;
 
	bool registered = m_storageBackend->getUser(row.jid, dummy);
 

	
 
	if (registered && !allowPasswordChange) {
 
		m_storageBackend->setUser(row);
 
		doUserRegistration(row);
 
		onUserRegistered(row);
 
	}
 

	
 
	return !registered;
 
}
 

	
 
bool UserRegistration::unregisterUser(const std::string &barejid) {
 
	UserInfo userInfo;
 
	bool registered = m_storageBackend->getUser(barejid, userInfo);
 

	
 
	// This user is not registered, nothing to do
 
	if (!registered) {
 
		return false;
 
	}
spectrum/src/frontends/slack/SlackFrontend.cpp
Show inline comments
 
@@ -113,17 +113,21 @@ void SlackFrontend::connectToServer() {
 
	LOG4CXX_INFO(logger, "Started.");
 
	m_transport->handleConnected();
 
}
 

	
 
std::string SlackFrontend::setOAuth2Code(const std::string &code, const std::string &state) {
 
	return static_cast<SlackUserManager *>(m_userManager)->handleOAuth2Code(code, state);
 
}
 

	
 
std::string SlackFrontend::getOAuth2URL(const std::vector<std::string> &args) {
 
	return static_cast<SlackUserManager *>(m_userManager)->getOAuth2URL(args);
 
}
 

	
 
std::string SlackFrontend::getRegistrationFields() {
 
	return "Slack team name\n3rd-party network username\n3rd-party network password";
 
}
 

	
 
void SlackFrontend::disconnectFromServer() {
 

	
 
}
 

	
 
}
spectrum/src/frontends/slack/SlackFrontend.h
Show inline comments
 
@@ -58,24 +58,25 @@ namespace Transport {
 
			virtual void sendIQ(boost::shared_ptr<Swift::IQ>);
 

	
 
			virtual void reconnectUser(const std::string &user);
 

	
 
			virtual RosterManager *createRosterManager(User *user, Component *component);
 
			virtual User *createUser(const Swift::JID &jid, UserInfo &userInfo, Component *component, UserManager *userManager);
 
			virtual UserManager *createUserManager(Component *component, UserRegistry *userRegistry, StorageBackend *storageBackend = NULL);
 
			virtual boost::shared_ptr<Swift::DiscoInfo> sendCapabilitiesRequest(Swift::JID to);
 
			virtual void clearRoomList();
 
			virtual void addRoomToRoomList(const std::string &handle, const std::string &name);
 
			virtual std::string setOAuth2Code(const std::string &code, const std::string &state);
 
			virtual std::string getOAuth2URL(const std::vector<std::string> &args);
 
			virtual std::string getRegistrationFields();
 
		
 
			void handleMessage(boost::shared_ptr<Swift::Message> message);
 

	
 
			ThreadPool *getThreadPool() {
 
				return m_tp;
 
			}
 

	
 
		private:
 
			Config* m_config;
 
			Swift::JID m_jid;
 
			Component *m_transport;
 
			UserManager *m_userManager;
spectrum_manager/src/html/login/index.html
Show inline comments
 
@@ -25,24 +25,25 @@
 
            <a class="menuitem" href="http://spectrum.im/documentation">Documentation</a>
 
            <a class="menuitem" href="http://spectrum.im/download">Download</a>
 
            <a class="menuitem" href="http://spectrum.im/discussion">Discussion</a>
 
            <a class="menuitem" href="https://github.com/hanzz/spectrum2/issues">Issue tracker</a>
 
            </section>-->
 
        </header>
 
    </div>
 

	
 
    <!-- MAIN CONTENT -->
 
    <div id="main_content_wrap" class="outer">
 
      <section id="main_content" class="inner">
 

	
 
      <p>If you don't have Spectrum 2 master account yet, you can <a href="/users">Register it here</a>. You will be able to manager your Spectrum 2 IM transports after that.</p>
 

	
 
<form action="/authorize" class="basic-grey" method="POST">
 
    <h1>Login form
 
        <span>Use your username and password to login to Spectrum 2 Manager.</span>
 
    </h1>
 
    <label>
 
        <span>Username:</span>
 
        <input type="text" id="user" name="user" placeholder="Username"></textarea>
 
    </label>
 
    <label>
 
        <span>Password:</span>
 
        <input type="password" id="password" name="password" placeholder="Password"></textarea>
spectrum_manager/src/server.cpp
Show inline comments
 
@@ -180,24 +180,26 @@ void Server::authorize(struct mg_connection *conn, struct http_message *hm) {
 

	
 
bool Server::is_authorized(const struct mg_connection *conn, struct http_message *hm) {
 
	Server::session *session;
 
	char valid_id[33];
 
	bool authorized = false;
 

	
 
	// Always authorize accesses to login page and to authorize URI
 
	if (!mg_vcmp(&hm->uri, "/login") ||
 
		!mg_vcmp(&hm->uri, "/login/") ||
 
		!mg_vcmp(&hm->uri, "/form.css") ||
 
		!mg_vcmp(&hm->uri, "/style.css") ||
 
		!mg_vcmp(&hm->uri, "/logo.png") ||
 
		!mg_vcmp(&hm->uri, "/users") ||
 
		!mg_vcmp(&hm->uri, "/users/add") ||
 
		!mg_vcmp(&hm->uri, "/authorize")) {
 
		return true;
 
	}
 

	
 
	if ((session = get_session(hm)) != NULL) {
 
		generate_session_id(valid_id, session->random, session->user);
 
		if (strcmp(valid_id, session->session_id) == 0) {
 
			session->expire = time(0) + SESSION_TTL;
 
			authorized = true;
 
		}
 
	}
 

	
 
@@ -306,109 +308,129 @@ void Server::serve_cmd(struct mg_connection *conn, struct http_message *hm) {
 
void Server::serve_logout(struct mg_connection *conn, struct http_message *hm) {
 
	Server:session *session = get_session(hm);
 
	mg_printf(conn, "HTTP/1.1 302 Found\r\n"
 
		"Set-Cookie: session=%s; max-age=0\r\n"  // Session ID
 
		"Location: /\r\n\r\n",
 
		session->session_id);
 

	
 
	sessions.erase(session->session_id);
 
	delete session;
 
}
 

	
 
void Server::serve_users_add(struct mg_connection *conn, struct http_message *hm) {
 
	Server:session *session = get_session(hm);
 
	if (!session->admin) {
 
		redirect_to(conn, hm, "/");
 
		return;
 
	}
 

	
 
	std::string user = get_http_var(hm, "user");
 
	std::string password = get_http_var(hm, "password");
 

	
 
	if (!user.empty() && !password.empty()) {
 
		if (m_storage) {
 
			UserInfo dummy;
 
			bool registered = m_storage->getUser(user, dummy);
 
			if (!registered) {
 
				UserInfo info;
 
				info.jid = user;
 
				info.password = password;
 
		if (m_storage) {
 
				m_storage->setUser(info);
 
			}
 
			else {
 
				redirect_to(conn, hm, "/users?error=This+username+is+already+registered");
 
				return;
 
			}
 
		}
 
	redirect_to(conn, hm, "/users");
 
	}
 
	redirect_to(conn, hm, "/users?ok=1");
 
}
 

	
 
void Server::serve_users_remove(struct mg_connection *conn, struct http_message *hm) {
 
	Server:session *session = get_session(hm);
 
	if (!session->admin) {
 
		redirect_to(conn, hm, "/");
 
		return;
 
	}
 

	
 
	if (!m_storage) {
 
		return;
 
	}
 

	
 
	std::string user = get_http_var(hm, "user");
 
	UserInfo info;
 
	m_storage->getUser(user, info);
 
	m_storage->removeUser(info.id);
 
	redirect_to(conn, hm, "/users");
 
}
 

	
 
void Server::serve_users(struct mg_connection *conn, struct http_message *hm) {
 
	std::string html = "<h2>Spectrum 2 manager users</h2>";
 

	
 
	std::string html;
 
	Server:session *session = get_session(hm);
 
	if (!session) {
 
		std::string ok = get_http_var(hm, "ok");
 
		if (!ok.empty()) {
 
			redirect_to(conn, hm, "/");
 
			return;
 
		}
 
		html += "<h2>Register new Spectrum 2 master account</h2>";
 
	}
 
	else {
 
		html += "<h2>Spectrum 2 manager users</h2>";
 

	
 
		if (!session->admin) {
 
			html += "<p>Only Spectrum 2 manager administrator can access this page.</p>";
 
			print_html(conn, hm, html);
 
			return;
 
		}
 

	
 
		html += "<p>Here, you can add new users who will have access to this web interface. "
 
				"These users will be able to register new accounts on all Spectrum 2 instances "
 
				"running on these server. They won't be able to change any Spectrum 2 instance "
 
				"configuration influencing other users.</p>";
 
	}
 

	
 
	std::string error = get_http_var(hm, "error");
 
	if (!error.empty()) {
 
		html += "<p><b>Error: " + error +  "</b></p>";
 
	}
 

	
 
	if (!m_storage) {
 
		print_html(conn, hm, html);
 
		return;
 
	}
 

	
 
	html += "<form action=\"/users/add\" class=\"basic-grey\" method=\"POST\"> \
 
	<h1>Add user \
 
		<span>Add new user to Spectrum 2 manager web interface.</span> \
 
	<h1>Register user \
 
		<span>Register new user to Spectrum 2 manager web interface.</span> \
 
	</h1> \
 
	<label> \
 
		<span>Username:</span> \
 
		<input type=\"text\" id=\"user\" name=\"user\"placeholder=\"Username\"></textarea> \
 
	</label> \
 
	<label><span>Password:</span> \
 
		<input type=\"password\" id=\"password\" name=\"password\" placeholder=\"Password\"></textarea> \
 
	</label> \
 
	<label> \
 
		<span>&nbsp;</span> \
 
		<input type=\"submit\" class=\"button\" value=\"Add user\" />\
 
	</label> \
 
</form><br/>";
 
	std::vector<std::string> users;
 
	m_storage->getUsers(users);
 

	
 
	if (session) {
 
		html += "<table><tr><th>User<th>Action</th></tr>";
 
		BOOST_FOREACH(std::string &user, users) {
 
			html += "<tr>";
 
			html += "<td><a href=\"/users?jid=" + user + "\">" + user + "</a></td>";
 
			html += "<td><a href=\"/users/remove?user=" + user + "\">Remove</a></td>";
 
			html += "</tr>";
 
		}
 
		html += "</table>";
 
	}
 

	
 
	print_html(conn, hm, html);
 
}
 

	
 
void Server::serve_instances_start(struct mg_connection *conn, struct http_message *hm) {
 
	Server:session *session = get_session(hm);
 
	if (!session->admin) {
 
		redirect_to(conn, hm, "/");
 
		return;
 
	}
 

	
 
	std::string html;
 
@@ -478,39 +500,50 @@ void Server::serve_instances_register(struct mg_connection *conn, struct http_me
 
		serve_instances(conn, hm);
 
		return;
 
	}
 

	
 
	std::string jid = get_http_var(hm, "jid");
 
	std::string uin = get_http_var(hm, "uin");
 
	std::string password = get_http_var(hm, "password");
 
	Server:session *session = get_session(hm);
 
	UserInfo info;
 
	m_storage->getUser(session->user, info);
 

	
 
	if (jid.empty() || uin.empty() || password.empty()) {
 
		std::string response = send_command(instance, "registration_fields");
 
		std::vector<std::string> fields;
 
		boost::split(fields, response, boost::is_any_of("\n"));
 

	
 
		if (fields.size() < 3) {
 
			fields.clear();
 
			fields.push_back("Jabber ID");
 
			fields.push_back("3rd-party network username");
 
			fields.push_back("3rd-party network password");
 
		}
 

	
 
		std::string html = "<h2>Register Spectrum 2 instance</h2>";
 
		html += "<form action=\"/instances/register\" class=\"basic-grey\" method=\"POST\"> \
 
			<h1>Register Spectrum 2 instance \
 
				<span>Write the Slack team name, 3rd-party network username and password.</span> \
 
				<span>Write the " + fields[0] + ", " + fields[1] + " and " + fields[2] + ".</span> \
 
			</h1> \
 
			<label> \
 
				<span>Slack team name:</span> \
 
				<input type=\"text\" id=\"jid\" name=\"jid\" placeholder=\"Slack team name\"></textarea> \
 
				<span>" + fields[0] + ":</span> \
 
				<input type=\"text\" id=\"jid\" name=\"jid\" placeholder=\""+ fields[0] +"\"></textarea> \
 
			</label> \
 
			<label> \
 
				<span>3rd-party network username:</span> \
 
				<input type=\"text\" id=\"uin\" name=\"uin\" placeholder=\"3rd-party network username\"></textarea> \
 
				<span>" + fields[1] + ":</span> \
 
				<input type=\"text\" id=\"uin\" name=\"uin\" placeholder=\"" + fields[1] + "\"></textarea> \
 
			</label> \
 
			<label><span>Password:</span> \
 
				<input type=\"password\" id=\"password\" name=\"password\" placeholder=\"3rd-party network password\"></textarea> \
 
			<label><span>" + fields[2] + ":</span> \
 
				<input type=\"password\" id=\"password\" name=\"password\" placeholder=\"" + fields[2] + "\"></textarea> \
 
			</label> \
 
			<label> \
 
				<span>&nbsp;</span> \
 
				<input type=\"submit\" class=\"button\" value=\"Register\" />\
 
			</label> \
 
			<input type=\"hidden\" name=\"instance\" value=\"" + instance + "\"></input> \
 
			</form><br/>";
 
		print_html(conn, hm, html);
 
	}
 
	else {
 
		std::string response = send_command(instance, "register " + jid + " " + uin + " " + password);
 
		if (!response.empty()) {
0 comments (0 inline, 0 general)