/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package com.celements.web.token;
import java.security.Principal;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.model.reference.WikiReference;
import org.xwiki.query.Query;
import org.xwiki.query.QueryException;
import org.xwiki.query.QueryManager;
import com.celements.web.service.IWebUtilsService;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.objects.BaseObject;
import com.xpn.xwiki.store.XWikiStoreInterface;
import com.xpn.xwiki.web.Utils;
public class NewCelementsTokenForUserCommand {
QueryManager injected_queryManager;
private static Log LOGGER = LogFactory.getFactory().getInstance(
NewCelementsTokenForUserCommand.class);
/**
* @param accountName
* @param guestPlus.
* if user is XWiki.XWikiGuest and guestPlus is true the account
* XWiki.XWikiGuestPlus will be used to get the token.
* @param context
* @return token (or null if token can not be generated)
* @throws XWikiException
*/
public String getNewCelementsTokenForUser(String accountName, Boolean guestPlus,
XWikiContext context) throws XWikiException {
return getNewCelementsTokenForUser(accountName, guestPlus, 1440, context);
}
/**
* @param accountName
* @param guestPlus.
* if user is XWiki.XWikiGuest and guestPlus is true the account
* XWiki.XWikiGuestPlus will be used to get the token.
* @param minutesValid
* how long should the token be valid in minutes.
* @param context
* @return token (or null if token can not be generated)
* @throws XWikiException
*/
public String getNewCelementsTokenForUser(String accountName, Boolean guestPlus, int minutesValid,
XWikiContext context) throws XWikiException {
LOGGER.debug("getNewCelementsTokenForUser: check for expired tokens.");
LOGGER.debug("getNewCelementsTokenForUser: with guestPlus [" + guestPlus + "] for account ["
+ accountName + "].");
String validkey = null;
if (guestPlus && "XWiki.XWikiGuest".equals(accountName)) {
accountName = "XWiki.XWikiGuestPlus";
}
XWikiDocument doc1 = context.getWiki().getDocument(accountName, context);
if (context.getWiki().exists(accountName, context) && (doc1.getObject(
"XWiki.XWikiUsers") != null)) {
removeOutdatedTokens(doc1);
validkey = getUniqueValidationKey(context);
BaseObject obj = doc1.newObject("Classes.TokenClass", context);
obj.set("tokenvalue", validkey, context);
Calendar myCal = Calendar.getInstance();
myCal.add(Calendar.MINUTE, minutesValid);
obj.set("validuntil", myCal.getTime(), context);
context.getWiki().saveDocument(doc1, context);
LOGGER.debug("getNewCelementsTokenForUser: sucessfully created token for account ["
+ accountName + "].");
}
return validkey;
}
synchronized void removeOutdatedTokens(XWikiDocument userDoc) {
String xwql = "select obj.number "
+ "from Document as doc, doc.object(Classes.TokenClass) as obj "
+ "where doc.fullName = :doc and obj.validuntil < :now order by obj.number desc";
try {
DocumentReference docRef = userDoc.getDocumentReference();
Query query = getQueryManagerComponent().createQuery(xwql, Query.XWQL);
query.bindValue("now", new Date());
query.bindValue("doc", getWebUtilsService().getRefLocalSerializer().serialize(docRef));
query.setWiki(docRef.getLastSpaceReference().getParent().getName());
List<Object> tokenResults = query.execute();
LOGGER.trace("userDoc: " + userDoc);
LOGGER.trace("Tokens to delete: " + tokenResults.size() + " in wiki "
+ docRef.getLastSpaceReference().getParent().getName());
DocumentReference tokenClassRef = getTokenClassDocRef(new WikiReference(
userDoc.getDocumentReference().getLastSpaceReference().getParent()));
for (Object retNr : tokenResults) {
int nr = Integer.parseInt(retNr.toString());
BaseObject obj = userDoc.getXObject(tokenClassRef, nr);
LOGGER.trace("deleting token " + nr + " of ref '" + tokenClassRef + "' obj is " + obj);
if (obj != null) {
userDoc.removeXObject(obj);
}
}
} catch (QueryException qe) {
LOGGER.error("Exception querying for outdated tokens with xwql [" + xwql + "]", qe);
}
}
DocumentReference getTokenClassDocRef(WikiReference wikiRef) {
return new DocumentReference(wikiRef.getName(), "Classes", "TokenClass");
}
QueryManager getQueryManagerComponent() {
if (injected_queryManager != null) {
return injected_queryManager;
}
return Utils.getComponent(QueryManager.class);
}
IWebUtilsService getWebUtilsService() {
return Utils.getComponent(IWebUtilsService.class);
}
public String getUniqueValidationKey(XWikiContext context) throws XWikiException {
XWikiStoreInterface storage = context.getWiki().getStore();
String hql = "select str.value from BaseObject as obj, StringProperty as str ";
hql += "where obj.className='XWiki.XWikiUsers' ";
hql += "and obj.id=str.id.id ";
hql += "and str.id.name='validkey' ";
hql += "and str.value<>''";
List<String> existingKeys = storage.search(hql, 0, 0, context);
String validkey = "";
while (validkey.equals("") || existingKeys.contains(validkey)) {
validkey = context.getWiki().generateRandomString(24);
}
return validkey;
}
/**
* @param accountName
* @param guestPlus.
* if user is XWiki.XWikiGuest and guestPlus is true the account
* XWiki.XWikiGuestPlus will be used to get the token.
* @param context
* @param minutesValid
* @return token (or null if token can not be generated)
* @throws XWikiException
*/
public String getNewCelementsTokenForUserWithAuthentication(String accountName, Boolean guestPlus,
int minutesValid, XWikiContext context) throws XWikiException {
accountName = authenticateForRequest(accountName, context);
return getNewCelementsTokenForUser(accountName, guestPlus, minutesValid, context);
}
/**
* @param accountName
* @param guestPlus.
* if user is XWiki.XWikiGuest and guestPlus is true the account
* XWiki.XWikiGuestPlus will be used to get the token.
* @param context
* @return token (or null if token can not be generated)
* @throws XWikiException
*/
public String getNewCelementsTokenForUserWithAuthentication(String accountName, Boolean guestPlus,
XWikiContext context) throws XWikiException {
accountName = authenticateForRequest(accountName, context);
return getNewCelementsTokenForUser(accountName, guestPlus, context);
}
private String authenticateForRequest(String accountName, XWikiContext context)
throws XWikiException {
if (!"".equals(context.getRequest().getParameter("j_username")) && !"".equals(
context.getRequest().getParameter("j_password"))) {
LOGGER.info("getNewCelementsTokenForUser: trying to authenticate "
+ context.getRequest().getParameter("j_username"));
Principal principal = context.getWiki().getAuthService().authenticate(
context.getRequest().getParameter("j_username"), context.getRequest().getParameter(
"j_password"), context);
if (principal != null) {
LOGGER.info("getNewCelementsTokenForUser: successfully autenthicated "
+ principal.getName());
context.setUser(principal.getName());
accountName = principal.getName();
}
}
return accountName;
}
}