package jplagWebService.serverAccess;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Locale;
import java.util.Properties;
import java.util.TimeZone;
import java.util.regex.Pattern;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import jplagUtils.PropertiesLoader;
import jplagWebService.server.FinishRequestData;
import jplagWebService.server.JPlagException;
import jplagWebService.server.MailTemplate;
import jplagWebService.server.RequestData;
import jplagWebService.server.UserData;
import jplagWebService.server.UserDataArray;
import jplagWebService.server.UserInfo;
import jplagWebService.serverImpl.JPlagCentral;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
public class UserAdmin extends Thread {
private static final long ONEDAY = 86400000;
private boolean doStopUserAdmin = false;
public static final int USER_INVALID = 0;
public static final int USER_NORMAL = 1;
// public static final int USER_EXPIRED = 5;
// public static final int USER_DEACTIVATED = 10;
public static final int USER_GROUPADMIN = 64;
public static final int USER_JPLAGADMIN = 192;
public static final int USER_JPLAGADMINNOTIFY = 224; // (email notify)
public static final int USER_SERVERPAGE = 256;
public static final int MASK_DEVELOPER = 2;
public static final int MASK_EXPIRED = 4;
public static final int MASK_DEACTIVATED = 8;
public static final int MASK_REQUESTNOTIFY = 32;
public static final int MASK_ANYADMIN = 64;
public static final int MASK_JPLAGADMIN = 128;
public static final int MASK_SERVERPAGE = 256;
public static final int MASK_NOAUTOASKEXTEND = 512;
public static final String JPLAG_SERVER = "https://jplag.ipd.kit.edu/";
private Document doc = null;
private Element rootElement = null;
private File userFile = null;
private PrintWriter logWriter = null;
private PrintWriter mailLogWriter = null;
private HashMap<String, PassAndState> userPassList = new HashMap<String, PassAndState>();
private Object userPassListMutex = new Object();
private class PassAndState {
public String password;
public int state;
public PassAndState(String pass, int stat) {
password = pass;
state = stat;
}
}
private RequestAdmin requestAdmin = null;
public UserAdmin(String jplagHome) {
requestAdmin = new RequestAdmin(jplagHome);
userFile = new File(jplagHome + File.separator + "jplag_users.xml");
if (!userFile.exists())
create();
else
parse();
try {
logWriter = new PrintWriter(new FileWriter(new File(jplagHome + File.separator + "userAdmin.log"), true), true);
mailLogWriter = new PrintWriter(new FileWriter(new File(jplagHome + File.separator + "userAdminMail.log"), true), true);
} catch (java.io.IOException ex) {
System.out.println("UserAdmin: Unable to open log files!");
}
}
public RequestAdmin getRequestAdmin() {
return requestAdmin;
}
private synchronized void log(String str) {
if (logWriter != null)
logWriter.println(str);
}
/**
* Writes the "jplag-users" data to an XML file
*/
private synchronized void writeXMLFile() {
try {
// Prepare the DOM document for writing
Source source = new DOMSource(doc);
// Prepare the output file
Result result = new StreamResult(userFile);
// Write the DOM document to the file
Transformer xformer = TransformerFactory.newInstance().newTransformer();
xformer.transform(source, result);
} catch (TransformerConfigurationException e) {
e.printStackTrace();
} catch (TransformerException e) {
e.printStackTrace();
}
}
/**
* Creates a new "jplag-user database" XML file
*/
private void create() {
DocumentBuilderFactory docBFac;
DocumentBuilder docBuild;
try {
docBFac = DocumentBuilderFactory.newInstance();
docBuild = docBFac.newDocumentBuilder();
doc = docBuild.newDocument();
} catch (Exception ex) {
ex.printStackTrace();
return;
}
rootElement = doc.createElement("jplag-users");
doc.appendChild(rootElement);
writeXMLFile();
}
/**
* Loads an existing "jplag-user database" into memory
*/
private void parse() {
try {
FileInputStream xmlStream = new FileInputStream(userFile);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setIgnoringComments(true);
DocumentBuilder builder = factory.newDocumentBuilder();
doc = builder.parse(xmlStream);
xmlStream.close();
rootElement = doc.getDocumentElement();
NodeList userList = rootElement.getElementsByTagName("user");
System.out.println("Number of users: " + userList.getLength());
synchronized (userPassListMutex) {
// avoid rehash operations during initialisation
userPassList = new HashMap<String, PassAndState>((int) (userList.getLength() * 1.4));
for (int j = 0; j < userList.getLength(); j++) {
Element user = (Element) userList.item(j);
userPassList.put(user.getAttribute("username"),
new PassAndState(user.getAttribute("password"), parseInt(user, "state")));
}
}
} catch (javax.xml.parsers.ParserConfigurationException e) {
// throw new RuntimeException("Failed to create DocumentBuilder");
e.printStackTrace();
} catch (org.xml.sax.SAXException e) {
// throw new RuntimeException("Error parsing users.xml");
e.printStackTrace();
} catch (Exception e) {
System.out.println("File error!");
e.printStackTrace();
}
}
/**
* Checks whether the given user already exists
*/
public boolean exists(String username) {
boolean ret;
synchronized (userPassListMutex) {
ret = userPassList.containsKey(username);
}
return ret;
}
/**
* Checks whether the given username is valid
*/
public boolean isValidUsername(String username) {
return Pattern.matches("^[\\w\\@\\.]+$", username);
}
public int getLoginState(String username, String password) {
synchronized (userPassListMutex) {
if (userPassList.containsKey(username)) {
PassAndState pas = (PassAndState) userPassList.get(username);
if (!pas.password.equals(password))
return USER_INVALID;
return pas.state;
}
}
return USER_INVALID;
}
/**
* Returns the user XML element for the given username
*/
private Element getUserXMLElement(String username) {
NodeList userList = rootElement.getElementsByTagName("user");
for (int i = 0; i < userList.getLength(); i++) {
Element elem = (Element) userList.item(i);
if (elem.getAttribute("username").equals(username))
return elem;
}
return null;
}
private void setString(Element elem, String attrname, String str) {
String old = elem.getAttribute(attrname);
if (old.equals(str))
return;
log(" " + attrname + ": " + old + " -> " + str);
elem.setAttribute(attrname, str);
}
private void setNillableString(Element elem, String attrname, String str) {
if (str == null || str.length() == 0) {
if (elem.hasAttribute(attrname)) {
log(" " + attrname + ": " + elem.getAttribute(attrname) + " gets deleted");
elem.removeAttribute(attrname);
}
} else
setString(elem, attrname, str);
}
private String parseNillableString(Element elem, String attrname) {
String str = elem.getAttribute(attrname);
if (str.length() == 0)
return null;
else
return str;
}
private static String formatCalendar(Calendar cal) {
DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.GERMAN);
return df.format(cal.getTime());
}
private void setNillableCalendar(Element user, String attr, Calendar cal) {
setNillableString(user, attr, (cal == null) ? null : formatCalendar(cal));
}
private static Calendar parseCalendar(String str) {
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
try {
cal.setTime(DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.GERMAN).parse(str));
} catch (java.text.ParseException ex) {
System.out.println("Illegal date: \"" + str + "\"");
cal.set(1970, 0, 1); // set an error date (1.1.1970)
System.out.println("Set to " + formatCalendar(cal));
}
return cal;
}
private static Calendar parseCalendar(Element elem, String attrname) {
return parseCalendar(elem.getAttribute(attrname));
}
private static Calendar parseNillableCalendar(String str) {
if (str.length() == 0)
return null;
else
return parseCalendar(str);
}
public static Calendar parseNillableCalendar(Element elem, String attrname) {
return parseNillableCalendar(elem.getAttribute(attrname));
}
public static int parseInt(Element elem, String attrname) {
int val;
try {
val = Integer.parseInt(elem.getAttribute(attrname));
} catch (NumberFormatException ex) {
System.out.println("Illegal " + attrname + " int: \"" + elem.getAttribute(attrname) + "\"");
val = -1;
}
return val;
}
public synchronized int getState(String name) {
Element user = getUserXMLElement(name);
int val = parseInt(user, "state");
if (val < 0)
return USER_INVALID;
else
return val;
}
public synchronized UserInfo getUserInfo(String username, int leftSlots) {
Element elem = getUserXMLElement(username);
Calendar expires = parseNillableCalendar(elem, "expires");
String email = elem.getAttribute("email");
String emailSecond = parseNillableString(elem, "emailSecond");
String homepage = parseNillableString(elem, "homepage");
return new UserInfo(leftSlots, expires, email, emailSecond, homepage);
}
public synchronized void updateUserInfo(String username, String newpassword, String newemailsecond, String newhomepage)
throws JPlagException {
Element elem = (Element) getUserXMLElement(username);
log("[" + new Date() + "] " + username + " called updateUserInfo:");
if (newpassword != null) {
if (newpassword.length() < 6)
throw new JPlagException("updateUserInfo", "The password is too short!", "The password must have at least 6 characters!");
setString(elem, "password", newpassword);
synchronized (userPassListMutex) {
userPassList.put(username, new PassAndState(newpassword, parseInt(elem, "state")));
}
}
if (newemailsecond != null)
setNillableString(elem, "emailSecond", newemailsecond);
if (newhomepage != null)
setNillableString(elem, "homepage", newhomepage);
writeXMLFile();
}
/**
* If isGroupAdmin is false, it returns a list of all users.<br>
* If isGroupAdmin is true, it returns a list of all users he created with
* the password set to an empty string.<br>
*
* @return A list of userdata elements in form of an ArrayOfUserData element
*/
public synchronized UserDataArray getUserDataArray(String calling_username, boolean isGroupAdmin) throws JPlagException {
NodeList userList = rootElement.getElementsByTagName("user");
int num;
if (isGroupAdmin) {
num = 0;
for (int i = 0; i < userList.getLength(); i++)
if (((Element) userList.item(i)).getAttribute("createdBy").equals(calling_username))
num++;
} else
num = userList.getLength();
UserData[] data = new UserData[num];
for (int i = 0, j = 0; i < userList.getLength(); i++) {
Element elem = (Element) userList.item(i);
if (!isGroupAdmin || elem.getAttribute("createdBy").equals(calling_username)) {
data[j] = new UserData();
data[j].setUsername(elem.getAttribute("username"));
data[j].setPassword(isGroupAdmin ? "" : elem.getAttribute("password"));
data[j].setCreated(parseCalendar(elem, "created"));
data[j].setCreatedBy(elem.getAttribute("createdBy"));
data[j].setExpires(parseNillableCalendar(elem, "expires"));
data[j].setLastUsage(parseNillableCalendar(elem, "lastUsage"));
data[j].setNumOfSubs(parseInt(elem, "numOfSubs"));
data[j].setRealName(elem.getAttribute("realname"));
data[j].setEmail(elem.getAttribute("email"));
data[j].setEmailSecond(parseNillableString(elem, "emailSecond"));
data[j].setHomepage(parseNillableString(elem, "homepage"));
data[j].setReason(elem.getAttribute("reason"));
data[j].setNotes(parseNillableString(elem, "notes"));
data[j].setState(parseInt(elem, "state"));
j++;
}
}
return new UserDataArray(data);
}
/**
* This function only creates a new user element. It does only initialise
* "createdBy", "numOfSubs" and "state"!
*/
private Element getNewUserElement(String creator) {
Element newuser = doc.createElement("user");
newuser.setAttribute("createdBy", creator);
newuser.setAttribute("numOfSubs", "0");
newuser.setAttribute("state", USER_NORMAL + "");
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
newuser.setAttribute("created", formatCalendar(cal));
return newuser;
}
/**
* Sets userdata fields, adds a new user or deletes one. Group admins can
* only change their "own" users and can not change the "createdBy" and
* "state" fields. For JPlag admins the "createdBy" field has to point to a
* valid user!
*/
public synchronized void setUserData(UserData data, String oldUsername, String calling_username, boolean isGroupAdmin)
throws JPlagException {
Element user;
log("[" + new Date() + "] " + calling_username + " called setUserData " + "for user " + oldUsername + " :");
if (oldUsername == null) // create a new user?
{
if (data.getUsername() == null)
throw new JPlagException("setUserData", "Illegal parameters! " + "oldUsername and username is null!", "Find out what "
+ "you want, create an user or delete one!");
if (!isValidUsername(data.getUsername()))
throw new JPlagException("setUserData", "Illegal new username!", "The username may only consist of the "
+ "following characters: 'A'-'Z', 'a'-'z', '0'-'9', " + "'@' and '.'");
if (exists(data.getUsername()))
throw new JPlagException("setUserData", "Adding a new user " + "with an already existing name!", "Try another name!");
log(" " + calling_username + " generates new user " + data.getUsername());
user = getNewUserElement(calling_username);
} else
user = getUserXMLElement(oldUsername);
if (user == null)
throw new JPlagException("setUserData", "User doesn't exist (anymore?)!", "Please update the user list!");
if (data.getUsername() == null) // delete user username?
{
if (isGroupAdmin && !calling_username.equals(user.getAttribute("createdBy"))) {
// log invalid access, wait a bit and throw an exception
System.out.println("setUserData: group admin " + calling_username + " tried to delete user " + oldUsername + " on "
+ new Date());
try {
Thread.sleep(10);
} catch (Exception ex) {
}
throw new JPlagException("setUserData", "You are not allowed" + "to delete this user!", "You can only delete users you"
+ " created! This has been logged.");
}
log(" deletes user " + oldUsername + " (real name: " + user.getAttribute("realname") + " email: " + user.getAttribute("email")
+ ")");
synchronized (userPassListMutex) {
userPassList.remove(oldUsername);
}
AccessStructure[] accStructs = JPlagCentral.listAccessStructures(oldUsername);
for (int i = 0; i < accStructs.length; i++)
JPlagCentral.cancelSubmission(accStructs[i]);
rootElement.removeChild(user);
} else {
if (isGroupAdmin && !calling_username.equals(user.getAttribute("createdBy"))) {
// log invalid access, wait a bit and throw an exception
System.out.println("setUserData: group admin " + calling_username + " tried to change fields for user "
+ data.getUsername() + " on " + new Date());
try {
Thread.sleep(10);
} catch (Exception ex) {
}
throw new JPlagException("setUserData", "You are not allowed" + "to change this user!", "You can only change users you"
+ " created! This has been logged.");
}
if (!user.getAttribute("username").equals(data.getUsername())) {
if (!isValidUsername(data.getUsername()))
throw new JPlagException("setUserData", "Illegal new username!", "The username may only consist of the "
+ "following characters: 'A'-'Z', 'a'-'z', " + "'0'-'9', '@' and '.'");
if (exists(data.getUsername()))
throw new JPlagException("setUserData", "Changing an username to an already existing name!", "Try another name!");
setString(user, "username", data.getUsername());
synchronized (userPassListMutex) {
userPassList.remove(oldUsername);
userPassList.put(data.getUsername(), new PassAndState(user.getAttribute("password"), parseInt(user, "state")));
}
}
if (data.getPassword().length() != 0 && !user.getAttribute("password").equals(data.getPassword())) {
setString(user, "password", data.getPassword());
synchronized (userPassListMutex) {
userPassList.put(user.getAttribute("username"), new PassAndState(data.getPassword(), parseInt(user, "state")));
}
}
setNillableCalendar(user, "expires", data.getExpires());
setString(user, "realname", data.getRealName());
setString(user, "email", data.getEmail());
setNillableString(user, "emailSecond", data.getEmailSecond());
setNillableString(user, "homepage", data.getHomepage());
setString(user, "reason", data.getReason());
setNillableString(user, "notes", data.getNotes());
if (!isGroupAdmin) {
setString(user, "created", formatCalendar(data.getCreated()));
setString(user, "createdBy", data.getCreatedBy());
setNillableCalendar(user, "lastUsage", data.getLastUsage());
setString(user, "numOfSubs", data.getNumOfSubs() + "");
if (parseInt(user, "state") != data.getState()) {
setString(user, "state", data.getState() + "");
synchronized (userPassListMutex) {
userPassList.put(user.getAttribute("username"), new PassAndState(user.getAttribute("password"), data.getState()));
}
}
} else {
if (parseInt(user, "state") != data.getState()) {
switch (data.getState() & ~MASK_DEVELOPER) {
case USER_NORMAL:
case MASK_EXPIRED:
case MASK_DEACTIVATED:
setString(user, "state", data.getState() + "");
synchronized (userPassListMutex) {
userPassList.put(user.getAttribute("username"),
new PassAndState(user.getAttribute("password"), data.getState()));
}
break;
default:
// log illegal state
System.out.println("setUserData: group admin " + calling_username + " tried to set " + data.getUsername()
+ "'s state to " + data.getState() + " on " + new Date());
break;
}
}
}
if (oldUsername == null) // create new user?
rootElement.appendChild(user);
checkExpired(user);
}
writeXMLFile();
}
private boolean updateCalendar(Element elem) {
Calendar curcal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
Calendar cal = parseCalendar(elem, "lastUsage");
if (curcal.get(Calendar.DAY_OF_MONTH) != cal.get(Calendar.DAY_OF_MONTH) || curcal.get(Calendar.MONTH) != cal.get(Calendar.MONTH)
|| curcal.get(Calendar.YEAR) != cal.get(Calendar.YEAR)) {
elem.setAttribute("lastUsage", formatCalendar(curcal));
return true;
}
return false;
}
public synchronized void updateLastUsage(String username) {
Element elem = getUserXMLElement(username);
if (updateCalendar(elem))
writeXMLFile();
}
public synchronized void incrementSubmissionCounter(String username) {
Element elem = getUserXMLElement(username);
int subs = parseInt(elem, "numOfSubs");
elem.setAttribute("numOfSubs", (subs + 1) + "");
updateCalendar(elem); // just in case a client runs a few months ;)
writeXMLFile();
}
/**
* Called by an AdminTool client from a user with administrator rights.
* Accepts or declines a specified request
*/
public synchronized boolean finishAccountRequest(FinishRequestData data, String adminname) throws JPlagException {
RequestData rd = requestAdmin.getRequestData(data.getOldUsername());
if (rd == null)
throw new JPlagException("requestAccount", "Request doesn't exist (anymore)!",
"Wrong username or this request has already been decided!");
if (data.getPassword() != null) // user not dismissed?
{
// User accepted, add to user database
UserData ud = new UserData(data.getUsername(), data.getPassword(), new GregorianCalendar(TimeZone.getTimeZone("GMT")),
adminname, data.getExpires(), null, 0, data.getRealName(), data.getEmail(), data.getEmailSecond(), data.getHomepage(),
data.getReason(), data.getNotes(), data.getState());
setUserData(ud, null, adminname, false);
}
if (data.getMailSubject() != null && data.getMailSubject().length() != 0) {
// inform user about acception or dismiss
sendMail(data.getEmail(), data.getMailSubject(), data.getMailMessage());
}
// Remove request from request list
requestAdmin.removeRequest(data.getOldUsername());
return true;
}
/**
* Called by the server page. - If everything but username is null, it
* returns, whether the username is OK (true) or it is already used (false).
* - If everything but password is null and password is the email validation
* code sent to the user, the request becomes available to the AdminTool and
* an email is sent to the administrator, if the code is wrong, false is
* returned. - If username, password, realname, email and reason is not
* null, it saves the data and sends a validation email to the user. -
* Otherwise an exception is thrown.
*/
public synchronized boolean requestAccount(RequestData data) throws JPlagException {
if (data.getRealName() == null && data.getEmail() == null && data.getEmailSecond() == null && data.getHomepage() == null
&& data.getReason() == null && data.getNotes() == null) {
if (data.getPassword() == null && data.getUsername() != null) {
if (exists(data.getUsername()))
return false;
else
return !requestAdmin.exists(data.getUsername());
} else if (data.getPassword() != null && data.getUsername() == null) {
String username = requestAdmin.validateRequest(data.getPassword());
RequestData rd = requestAdmin.getRequestData(username);
// Send notification messages to all administrators with
// notification to make them notice the new validated request
NodeList userList = rootElement.getElementsByTagName("user");
for (int i = 0; i < userList.getLength(); i++) {
Element elem = (Element) userList.item(i);
if ((parseInt(elem, "state") & MASK_REQUESTNOTIFY) != 0) {
sendMail(elem.getAttribute("email"), MailTemplateAdmin.SERVER_REQUESTNOTIFY, rd);
}
}
return true;
}
}
if (data.getUsername() == null || data.getPassword() == null || data.getRealName() == null || data.getEmail() == null
|| data.getReason() == null)
throw new JPlagException("requestAccount", "Username, password, " + "real name, primary email or reason is missing!",
"Check your input!");
if (!isValidUsername(data.getUsername()))
throw new JPlagException("requestAccount", "Illegal new username!", "The username may only consist of the "
+ "following characters: 'A'-'Z', 'a'-'z', " + "'0'-'9', '@' and '.'");
if (exists(data.getUsername()) || requestAdmin.exists(data.getUsername()))
throw new JPlagException("requestAccount", "Username already used!", "Seems like somebody else was faster ;)");
// Everything's fine, so add request to unverificated request list
// and send a verification mail
String vericode = requestAdmin.addRequest(data);
sendMail(data.getEmail(), MailTemplateAdmin.SERVER_VERIFICATION, data, "code", vericode);
return true;
}
public void extendAccount(String extendCode) throws JPlagException {
if (extendCode.length() >= 12) // username must be at least one character
{
String username = extendCode.substring(11);
System.out.println("[" + new Date() + "] extendAccount: username=" + username + " code=" + extendCode);
Element userElem = getUserXMLElement(username);
if (userElem != null) {
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
if (userElem.getAttribute("askExtendCode").equals(extendCode)) {
cal.add(Calendar.YEAR, 1);
setNillableCalendar(userElem, "expires", cal);
userElem.removeAttribute("expWarned");
userElem.removeAttribute("askExtendCode");
return;
} else {
Calendar expires = parseNillableCalendar(userElem, "expires");
if (expires != null) {
Calendar next2Week = (Calendar) cal.clone();
next2Week.add(Calendar.DATE, 14);
if (expires.after(next2Week)) {
throw new JPlagException("extendAccount", "Your account has already been extended!",
"You probably opened this page more than once and missed the result of the first time.");
}
}
}
}
}
throw new JPlagException("extendAccount", "Wrong extend code given: " + extendCode,
"Please check the correct spelling of the code!");
}
/**
* Sends a specified email to all developers
*/
public void notifyDevelopers(String subject, String message) throws JPlagException {
NodeList userList = rootElement.getElementsByTagName("user");
for (int i = 0; i < userList.getLength(); i++) {
Element elem = (Element) userList.item(i);
if ((parseInt(elem, "state") & MASK_DEVELOPER) != 0)
sendMail(elem.getAttribute("email"), subject, message);
}
}
/**
* Sets the developer flag for the specified user according to developer
*/
public synchronized void setDeveloperState(String username, boolean developer) throws JPlagException {
Element user = getUserXMLElement(username);
if (user == null)
throw new JPlagException("setDeveloperState", "User doesn't exist (anymore?)!", "Please update the user list!");
int state = parseInt(user, "state");
if (developer) {
if ((state & MASK_DEVELOPER) != 0)
throw new JPlagException("setDeveloperState", "You are already marked as a developer!", "Nothing changed.");
state |= MASK_DEVELOPER;
} else {
if ((state & MASK_DEVELOPER) == 0)
throw new JPlagException("setDeveloperState", "You are not marked as a developer!", "Nothing changed.");
state &= ~MASK_DEVELOPER;
}
user.setAttribute("state", state + "");
synchronized (userPassListMutex) {
PassAndState pas = (PassAndState) userPassList.get(username);
pas.state = state;
}
writeXMLFile();
}
public void stopUserAdmin() {
doStopUserAdmin = true;
}
/**
*
* @param elem
* User element to be checked
* @param cal
* Current date as calendar
* @param next2Week
* Date after which a expiration notice should be sent
*/
private void checkExpired(Element elem, Calendar cal, Calendar next2Week) {
Calendar expires = parseNillableCalendar(elem, "expires");
if (expires != null) {
int state = parseInt(elem, "state");
if ((state & (MASK_EXPIRED | MASK_DEACTIVATED)) == 0) {
if (cal.after(expires)) {
System.out.println("[" + new Date() + "] User " + elem.getAttribute("username") + " expired (expires="
+ elem.getAttribute("expires") + ")");
elem.setAttribute("state", (state | MASK_EXPIRED) + "");
synchronized (userPassListMutex) {
PassAndState pas = (PassAndState) userPassList.get(elem.getAttribute("username"));
pas.state = state | MASK_EXPIRED;
}
try {
sendMail(elem.getAttribute("email"), MailTemplateAdmin.SERVER_EXPIRED, elem);
} catch (JPlagException ex) {
System.out.println("Unable to send \"expired\" mail (" + ex.getExceptionType() + ": " + ex.getDescription() + "\n"
+ ex.getRepair());
ex.printStackTrace();
}
} else if (next2Week.after(expires)) {
if (!elem.hasAttribute("expWarned")) {
if ((state & MASK_NOAUTOASKEXTEND) == 0 && parseInt(elem, "numOfSubs") != 0) {
System.out.println("[" + new Date() + "] User " + elem.getAttribute("username")
+ " expires within two weeks! Asking for extend.");
try {
String extendCode = RequestAdmin.getRandomCode() + elem.getAttribute("username");
sendMail(elem.getAttribute("email"), MailTemplateAdmin.SERVER_ASKEXTEND, elem, "code", extendCode);
elem.setAttribute("expWarned", "");
elem.setAttribute("askExtendCode", extendCode);
} catch (JPlagException ex) {
System.out.println("Unable to send \"askExtend" + "\" mail (" + ex.getExceptionType() + ": "
+ ex.getDescription() + "\n" + ex.getRepair());
ex.printStackTrace();
}
} else {
System.out.println("[" + new Date() + "] User " + elem.getAttribute("username") + " expires within two weeks!");
try {
sendMail(elem.getAttribute("email"), MailTemplateAdmin.SERVER_WARNEXPIRE, elem);
elem.setAttribute("expWarned", "");
} catch (JPlagException ex) {
System.out.println("Unable to send \"warnExpire" + "\" mail (" + ex.getExceptionType() + ": "
+ ex.getDescription() + "\n" + ex.getRepair());
ex.printStackTrace();
}
}
}
return;
}
}
}
elem.removeAttribute("expWarned");
elem.removeAttribute("askExtendCode");
}
private void checkExpired(Element elem) {
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
Calendar next2Week = (Calendar) cal.clone();
next2Week.add(Calendar.DATE, 14);
checkExpired(elem, cal, next2Week);
}
public void run() {
System.out.println("[" + new Date() + "] UserAdministration started");
try {
while (!doStopUserAdmin) {
// remove expired users
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
Calendar next2Week = (Calendar) cal.clone();
next2Week.add(Calendar.DATE, 14);
synchronized (this) {
NodeList userList = rootElement.getElementsByTagName("user");
for (int i = userList.getLength() - 1; i >= 0; i--) {
Element elem = (Element) userList.item(i);
checkExpired(elem, cal, next2Week);
}
writeXMLFile();
}
// remove expired requests
requestAdmin.removeExpiredUnvalidatedRequests();
// get new current time
cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
long nowMillis = cal.getTimeInMillis();
try {
// wait until next midnight
long sleepTime = ONEDAY - (nowMillis + ONEDAY - 1) % ONEDAY;
String sleepTimeStr = ((sleepTime / 3600000 > 0) ? (sleepTime / 3600000) + " h " : "")
+ ((sleepTime / 60000 > 0) ? ((sleepTime / 60000) % 60) + " min " : "") + (sleepTime / 1000 % 60) + " sec";
System.out.println("[" + new Date() + "] UserAdmin: I'll " + "sleep for " + sleepTimeStr);
Thread.sleep(sleepTime);
} catch (InterruptedException ex) {
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
synchronized (this) {
logWriter.close();
mailLogWriter.close();
}
System.out.println("[" + new Date() + "] UserAdministration stopped!");
}
private class MailAuthenticator extends Authenticator {
String username, password;
public MailAuthenticator(String username, String password) {
super();
this.password = password;
this.username = username;
}
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(this.username, password);
}
}
private MailTemplate evalMailTemplate(String name, MailTemplateData data) {
MailTemplateAdmin mailTemplateAdmin = JPlagCentral.getInstance().getMailTemplateAdmin();
MailTemplate template = mailTemplateAdmin.getMailTemplate(MailTemplateAdmin.MAIL_SERVER, name);
if (template == null)
return null;
// Evaluate subject
template.setSubject(mailTemplateAdmin.evalTemplateString(template.getSubject(), data));
// Evaluate message body
template.setData(mailTemplateAdmin.evalTemplateString(template.getData(), data));
return template;
}
private void sendMail(String destMail, String name, MailTemplateData data) throws JPlagException {
MailTemplate mail = evalMailTemplate(name, data);
if (mail == null) {
System.out.println("UserAdmin.sendMail(): Unable to get \"" + name + "\" message!!");
throw new JPlagException("UserAdminException", "Internal server error: Unable to find mail template!",
"Please contact the JPlag admin!");
} else
sendMail(destMail, mail.getSubject(), mail.getData());
}
private void sendMail(String destMail, String name, RequestData data, String paramname, String param) throws JPlagException {
MailTemplateData tempData = new MailTemplateData(data);
if (paramname != null)
tempData.put(paramname, param);
sendMail(destMail, name, tempData);
}
private void sendMail(String destMail, String name, RequestData data) throws JPlagException {
sendMail(destMail, name, new MailTemplateData(data));
}
private void sendMail(String destMail, String name, Element elem, String paramname, String param) throws JPlagException {
MailTemplateData tempData = new MailTemplateData(elem);
if (paramname != null)
tempData.put(paramname, param);
sendMail(destMail, name, tempData);
}
private void sendMail(String destMail, String name, Element elem) throws JPlagException {
sendMail(destMail, name, new MailTemplateData(elem));
}
public void sendMail(String destMail, String subject, String message) throws JPlagException {
Properties mailProps = PropertiesLoader.loadProps("jplagWebService/serverAccess/mailconfig.properties");
// Gets the System properties
Properties l_props = System.getProperties();
// Puts the SMTP server name to properties object
l_props.put("mail.smtp.host", mailProps.getProperty("mail.smtp.host", "smtp.ira.uni-karlsruhe.de"));
l_props.put("mail.smtp.auth", mailProps.getProperty("mail.smtp.auth", "true"));
l_props.put("mail.smtp.starttls.enable", mailProps.getProperty("mail.smtp.starttls.enable", "true"));
l_props.put("mail.SSLSocketFactory.class",
mailProps.getProperty("mail.SSLSocketFactory.class", "jplagWebService.serverAccess.TrustAllSSLSocketFactory"));
// Get the default Session using Properties Object
Session session = Session.getInstance(l_props, new MailAuthenticator(
mailProps.getProperty("mail.smtp.auth.user", "jplag"),
mailProps.getProperty("mail.smtp.auth.pass", "zentis!?")));
//session.setDebug(true); // Enable the debug mode
try {
MimeMessage msg = new MimeMessage(session); // Create a New message
msg.setFrom(new InternetAddress(mailProps.getProperty("from_address", "smtp.ira.uni-karlsruhe.de")));
msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(destMail, false));
msg.setSubject(subject, "UTF-8");
msg.setContent(message, "text/plain; charset=UTF-8");
msg.setSentDate(new Date());
// Send the message
Transport.send(msg);
// If here, then message is successfully sent.
} catch (Exception e) {
System.out.println("Exception in sendMail: destMail=" + destMail);
e.printStackTrace();
throw new JPlagException("sendMail", "Exception caught: " + e.toString(), "Does this help?");
}
synchronized (this) {
if (mailLogWriter != null)
mailLogWriter.println("[" + new Date() + "] Sent the following " + "mail to " + destMail + ":\n\nSubject: " + subject
+ "\n\nMessage: " + message);
}
}
}