/*
* Copyright 2011-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.vertx.mods;
import org.vertx.java.busmods.BusModBase;
import org.vertx.java.core.Handler;
import org.vertx.java.core.eventbus.Message;
import org.vertx.java.core.json.JsonObject;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* Basic Authentication Manager Bus Module<p>
* Please see the busmods manual for a full description<p>
*
* @author <a href="http://tfox.org">Tim Fox</a>
*/
public class AuthManager extends BusModBase {
private Handler<Message<JsonObject>> loginHandler;
private Handler<Message<JsonObject>> logoutHandler;
private Handler<Message<JsonObject>> authoriseHandler;
protected final Map<String, String> sessions = new HashMap<>();
protected final Map<String, LoginInfo> logins = new HashMap<>();
private static final long DEFAULT_SESSION_TIMEOUT = 30 * 60 * 1000;
private String address;
private String userCollection;
private String persistorAddress;
private long sessionTimeout;
private static final class LoginInfo {
final long timerID;
final String sessionID;
private LoginInfo(long timerID, String sessionID) {
this.timerID = timerID;
this.sessionID = sessionID;
}
}
/**
* Start the busmod
*/
public void start() {
super.start();
this.address = getOptionalStringConfig("address", "vertx.basicauthmanager");
this.userCollection = getOptionalStringConfig("user_collection", "users");
this.persistorAddress = getOptionalStringConfig("persistor_address", "vertx.mongopersistor");
Number timeout = config.getNumber("session_timeout");
if (timeout != null) {
if (timeout instanceof Long) {
this.sessionTimeout = (Long)timeout;
} else if (timeout instanceof Integer) {
this.sessionTimeout = (Integer)timeout;
}
} else {
this.sessionTimeout = DEFAULT_SESSION_TIMEOUT;
}
loginHandler = new Handler<Message<JsonObject>>() {
public void handle(Message<JsonObject> message) {
doLogin(message);
}
};
eb.registerHandler(address + ".login", loginHandler);
logoutHandler = new Handler<Message<JsonObject>>() {
public void handle(Message<JsonObject> message) {
doLogout(message);
}
};
eb.registerHandler(address + ".logout", logoutHandler);
authoriseHandler = new Handler<Message<JsonObject>>() {
public void handle(Message<JsonObject> message) {
doAuthorise(message);
}
};
eb.registerHandler(address + ".authorise", authoriseHandler);
}
private void doLogin(final Message<JsonObject> message) {
final String username = getMandatoryString("username", message);
if (username == null) {
return;
}
String password = getMandatoryString("password", message);
if (password == null) {
return;
}
JsonObject findMsg = new JsonObject().putString("action", "findone").putString("collection", userCollection);
JsonObject matcher = new JsonObject().putString("username", username).putString("password", password);
findMsg.putObject("matcher", matcher);
eb.send(persistorAddress, findMsg, new Handler<Message<JsonObject>>() {
public void handle(Message<JsonObject> reply) {
if (reply.body.getString("status").equals("ok")) {
if (reply.body.getObject("result") != null) {
// Check if already logged in, if so logout of the old session
LoginInfo info = logins.get(username);
if (info != null) {
logout(info.sessionID);
}
// Found
final String sessionID = UUID.randomUUID().toString();
long timerID = vertx.setTimer(sessionTimeout, new Handler<Long>() {
public void handle(Long timerID) {
sessions.remove(sessionID);
logins.remove(username);
}
});
sessions.put(sessionID, username);
logins.put(username, new LoginInfo(timerID, sessionID));
JsonObject jsonReply = new JsonObject().putString("sessionID", sessionID);
sendOK(message, jsonReply);
} else {
// Not found
sendStatus("denied", message);
}
} else {
logger.error("Failed to execute login query: " + reply.body.getString("message"));
sendError(message, "Failed to excecute login");
}
}
});
}
protected void doLogout(final Message<JsonObject> message) {
final String sessionID = getMandatoryString("sessionID", message);
if (sessionID != null) {
if (logout(sessionID)) {
sendOK(message);
} else {
super.sendError(message, "Not logged in");
}
}
}
protected boolean logout(String sessionID) {
String username = sessions.remove(sessionID);
if (username != null) {
LoginInfo info = logins.remove(username);
vertx.cancelTimer(info.timerID);
return true;
} else {
return false;
}
}
protected void doAuthorise(Message<JsonObject> message) {
String sessionID = getMandatoryString("sessionID", message);
if (sessionID == null) {
return;
}
String username = sessions.get(sessionID);
// In this basic auth manager we don't do any resource specific authorisation
// The user is always authorised if they are logged in
if (username != null) {
JsonObject reply = new JsonObject().putString("username", username);
sendOK(message, reply);
} else {
sendStatus("denied", message);
}
}
}