/*
* 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.xpn.xwiki.api;
import java.text.MessageFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xwiki.model.EntityType;
import org.xwiki.model.reference.DocumentReferenceResolver;
import org.xwiki.model.reference.EntityReference;
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.objects.classes.PasswordClass;
import com.xpn.xwiki.user.api.XWikiUser;
import com.xpn.xwiki.util.Programming;
import com.xpn.xwiki.web.Utils;
/**
* Scriptable API for easy handling of users. For the moment this API is very limited, containing only one method. In
* the future it should be extended to provide useful methods for working with users.
*
* @version $Id: ab07a34bc2eab9487335b83582edef8c3c2ad926 $
* @since Platform-1.0
*/
public class User extends Api
{
/** Logging helper object. */
protected static final Logger LOGGER = LoggerFactory.getLogger(User.class);
/** User class reference. */
private static final EntityReference USERCLASS_REFERENCE = new EntityReference("XWikiUsers", EntityType.DOCUMENT,
new EntityReference("XWiki", EntityType.SPACE));
/** Reference resolver. */
private static final DocumentReferenceResolver<String> REFERENCE_RESOLVER = Utils.getComponent(
DocumentReferenceResolver.TYPE_STRING, "currentmixed");
/** The wrapped XWikiUser object. */
private XWikiUser user;
/**
* Constructs a wrapper for the given protected XWikiUser object.
*
* @param user The XWikiUser object that should be wrapper.
* @param context The current {@link XWikiContext context}.
*/
public User(XWikiUser user, XWikiContext context)
{
super(context);
this.user = user;
}
/**
* Expose the wrapped XWikiUser object. Requires programming rights.
*
* @return The wrapped XWikiUser object, or <tt>null</tt> if the user does not have programming rights.
*/
@Programming
public XWikiUser getUser()
{
if (hasProgrammingRights()) {
return this.user;
}
return null;
}
/**
* Check if the user belongs to a group or not. This method only check direct membership (no recursive checking) in
* the current wiki.
*
* @param groupName The group to check.
* @return <tt>true</tt> if the user does belong to the specified group, false otherwise or if an exception occurs.
*/
public boolean isUserInGroup(String groupName)
{
boolean result = false;
try {
if (this.user == null) {
LOGGER.warn("User considered not part of group [{}] since user is null", groupName);
} else {
result = this.user.isUserInGroup(groupName, getXWikiContext());
}
} catch (Exception ex) {
LOGGER.warn(new MessageFormat("Unhandled exception while checking if user {0}"
+ " belongs to group {1}").format(new java.lang.Object[] { this.user, groupName }), ex);
}
return result;
}
/**
* <p>
* See if the user is global (i.e. registered in the main wiki) or local to a virtual wiki.
* </p>
* <p>
* This method is not public, as the underlying implementation is not fully functional
* </p>
*
* @return <tt>true</tt> if the user is global, false otherwise or if an exception occurs.
*/
protected boolean isMain()
{
return this.user.isMain();
}
/**
* API to retrieve the e-mail address of this user. This e-mail address is taken from the user profile. If the user
* hasn't changed his profile, then this is the e-mail address he filled in the registration form.
*
* @return The e-mail address from the user profile, or <tt>null</tt> if there is an error retrieving the email.
* @since 1.1.3
* @since 1.2.2
* @since 1.3M2
*/
public String getEmail()
{
XWikiDocument userDoc;
try {
userDoc = getXWikiContext().getWiki().getDocument(this.user.getUser(), getXWikiContext());
BaseObject obj = userDoc.getObject("XWiki.XWikiUsers");
return obj.getStringValue("email");
} catch (Exception e) {
// APIs should never throw errors, as velocity cannot catch them, and scripts should be
// as robust as possible. Instead, the code using this should know that null means there
// was an error, if it really needs to report these exceptions.
return null;
}
}
/**
* Check if the password passed as argument is the user password. This method is used when a user wants to change
* its password. To make sure that it wouldn't be used to perform brute force attacks, we ensure that this is only
* used to check the current user password on its profile page.
*
* @param password Password submitted.
* @return true if password is really the user password.
* @throws XWikiException error if authorization denied.
*/
public boolean checkPassword(String password) throws XWikiException
{
EntityReference userReference = REFERENCE_RESOLVER.resolve(this.user.getUser());
EntityReference docReference = getXWikiContext().getDoc().getDocumentReference();
if (userReference.equals(getXWikiContext().getUserReference()) && userReference.equals(docReference)) {
try {
boolean result = false;
XWikiDocument userDoc = getXWikiContext().getWiki().getDocument(userReference, getXWikiContext());
BaseObject obj = userDoc.getXObject(USERCLASS_REFERENCE);
// We only allow empty password from users having a XWikiUsers object.
if (obj != null) {
final String stored = obj.getStringValue("password");
result = new PasswordClass().getEquivalentPassword(stored, password).equals(stored);
}
return result;
} catch (Throwable e) {
LOGGER.error("Failed to check password", e);
return false;
}
} else {
throw new XWikiException(XWikiException.MODULE_XWIKI_ACCESS, XWikiException.ERROR_XWIKI_ACCESS_DENIED,
"You cannot use this method for checking another user password.", null);
}
}
}