/*
* Tigase Jabber/XMPP Server
* Copyright (C) 2004-2012 "Artur Hefczyc" <artur.hefczyc@tigase.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. Look for COPYING file in the top folder.
* If not, see http://www.gnu.org/licenses/.
*
* $Rev$
* Last modified by $Author$
* $Date$
*/
package tigase.xmpp;
//~--- non-JDK imports --------------------------------------------------------
import tigase.db.AuthRepository;
import tigase.db.AuthorizationException;
import tigase.db.TigaseDBException;
import tigase.db.UserExistsException;
import tigase.db.UserNotFoundException;
import tigase.db.UserRepository;
import tigase.util.TigaseStringprepException;
import tigase.vhosts.VHostItem;
import static tigase.db.NonAuthUserRepository.*;
//~--- JDK imports ------------------------------------------------------------
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
//~--- classes ----------------------------------------------------------------
/**
* Describe class RepositoryAccess here.
*
*
* Created: Tue Oct 24 10:38:41 2006
*
* @author <a href="mailto:artur.hefczyc@tigase.org">Artur Hefczyc</a>
* @version $Rev$
*/
public abstract class RepositoryAccess {
/**
* Private logger for class instancess.
*/
private static final Logger log = Logger.getLogger("tigase.xmpp.RepositoryAccess");
protected static final String NOT_AUTHORIZED_MSG =
"Session has not been yet authorised.";
protected static final String NO_ACCESS_TO_REP_MSG = "Can not access user repository.";
private static final String ANONYMOUS_MECH = "ANONYMOUS";
// ~--- fields ---------------------------------------------------------------
private AuthRepository authRepo = null;
protected VHostItem domain = null;
/**
* Handle to user repository - permanent data base for storing user data.
*/
private UserRepository repo = null;
// private boolean anon_allowed = false;
private boolean is_anonymous = false;
/**
* Current authorization state - initialy session i
* <code>NOT_AUTHORIZED</code>. It becomes <code>AUTHORIZED</code>
*/
private Authorization authState = Authorization.NOT_AUTHORIZED;
// ~--- constructors ---------------------------------------------------------
/**
* Creates a new <code>RepositoryAccess</code> instance.
*
*
* @param rep
* @param auth
*/
public RepositoryAccess(UserRepository rep, AuthRepository auth) {
repo = rep;
authRepo = auth;
// this.anon_allowed = anon_allowed;
}
// ~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*
* @throws NotAuthorizedException
*/
public abstract BareJID getBareJID() throws NotAuthorizedException;
/**
* Method description
*
*
* @return
*
* @throws NotAuthorizedException
*/
public abstract String getUserName() throws NotAuthorizedException;
// ~--- methods --------------------------------------------------------------
protected abstract void login();
/**
* Method description
*
*
* @param subnode
* @param key
* @param list
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public void addDataList(final String subnode, final String key, final String[] list)
throws NotAuthorizedException, TigaseDBException {
if (is_anonymous) {
return;
}
if (!isAuthorized()) {
throw new NotAuthorizedException(NO_ACCESS_TO_REP_MSG);
}
try {
repo.addDataList(getBareJID(), subnode, key, list);
} catch (UserNotFoundException e) {
log.log(Level.FINEST, "Problem accessing reposiotry: ", e);
throw new NotAuthorizedException(NO_ACCESS_TO_REP_MSG, e);
// } catch (TigaseDBException e) {
// log.log(Level.SEVERE, "Repository access exception.", e);
} // end of try-catch
}
/**
* Method description
*
*
* @param subnode
* @param key
* @param list
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public void addOfflineDataList(String subnode, String key, String[] list)
throws NotAuthorizedException, TigaseDBException {
addDataList(calcNode(OFFLINE_DATA_NODE, subnode), key, list);
}
/**
* Method description
*
*
* @param subnode
* @param key
* @param list
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public void addPublicDataList(String subnode, String key, String[] list)
throws NotAuthorizedException, TigaseDBException {
addDataList(calcNode(PUBLIC_DATA_NODE, subnode), key, list);
}
// ~--- get methods ----------------------------------------------------------
/**
* Gets the value of authState
*
* @return the value of authState
*/
public final Authorization getAuthState() {
return this.authState;
}
/**
* Method description
*
*
* @param xmpp_sessionId
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public String getAuthenticationToken(String xmpp_sessionId)
throws NotAuthorizedException, TigaseDBException {
UUID token = UUID.randomUUID();
setData("tokens", xmpp_sessionId, token.toString());
return token.toString();
}
/**
* <code>getData</code> method is a twin sister (brother?) of
* <code>setData(String, String, String)</code> method. It allows you to
* retrieve data stored with above method. It is data stored in given node
* with given key identifier. If there are no data associated with given key
* or given node does not exist given <code>def</code> value is returned.
*
* @param subnode
* a <code>String</code> value is path to node where pair
* <code>(key, value)</code> are stored.
* @param key
* a <code>String</code> value of key ID for data to retrieve.
* @param def
* a <code>String</code> value of default returned if there is
* nothing stored with given key. <code>def</code> can be set to any
* value you wish to have back as default value or <code>null</code>
* if you want to have back <code>null</code> if no data was found.
* If you set <code>def</code> to <code>null</code> it has exactly
* the same effect as if you use <code>getData(String)</code> method.
* @return a <code>String</code> value of data found for given key or
* <code>def</code> if there was no data associated with given key.
* @exception NotAuthorizedException
* is thrown when session has not been authorized yet and there
* is no access to permanent storage.
* @throws TigaseDBException
* @see #setData(String, String, String)
*/
public String getData(String subnode, String key, String def)
throws NotAuthorizedException, TigaseDBException {
if (is_anonymous) {
return null;
}
if (!isAuthorized()) {
throw new NotAuthorizedException(NO_ACCESS_TO_REP_MSG);
}
try {
return repo.getData(getBareJID(), subnode, key, def);
} catch (UserNotFoundException e) {
log.log(Level.FINEST, "Problem accessing reposiotry: ", e);
throw new NotAuthorizedException(NO_ACCESS_TO_REP_MSG, e);
// } catch (TigaseDBException e) {
// log.log(Level.SEVERE, "Repository access exception.", e);
} // end of try-catch
// return null;
}
/**
* This method retrieves list of all direct subnodes for given node. It works
* in similar way as <code>ls</code> unix command or <code>dir</code> under
* DOS/Windows systems.
*
* @param subnode
* a <code>String</code> value of path to node for which we want to
* retrieve list of direct subnodes.
* @return a <code>String[]</code> array of direct subnodes names for given
* node.
* @exception NotAuthorizedException
* is thrown when session has not been authorized yet and there
* is no access to permanent storage.
* @throws TigaseDBException
* @see #setData(String, String, String)
*/
public String[] getDataGroups(String subnode) throws NotAuthorizedException,
TigaseDBException {
if (is_anonymous) {
return null;
}
if (!isAuthorized()) {
throw new NotAuthorizedException(NO_ACCESS_TO_REP_MSG);
}
try {
return repo.getSubnodes(getBareJID(), subnode);
} catch (UserNotFoundException e) {
log.log(Level.FINEST, "Problem accessing reposiotry: ", e);
throw new NotAuthorizedException(NO_ACCESS_TO_REP_MSG, e);
// } catch (TigaseDBException e) {
// log.log(Level.SEVERE, "Repository access exception.", e);
} // end of try-catch
// return null;
}
/**
* This method returns all data keys available in permanent storage in given
* node. There is not though any information what kind of data is stored with
* this key. This is up to user (developer) to determine what data type is
* associated with key and what is it's meaning.
*
* @param subnode
* a <code>String</code> value pointing to specific subnode in user
* reposiotry where data have to be stored.
* @return a <code>String[]</code> array containing all data keys found in
* given subnode.
* @exception NotAuthorizedException
* is thrown when session has not been authorized yet and there
* is no access to permanent storage.
* @throws TigaseDBException
* @see #setData(String, String, String)
*/
public String[] getDataKeys(final String subnode) throws NotAuthorizedException,
TigaseDBException {
if (is_anonymous) {
return null;
}
if (!isAuthorized()) {
throw new NotAuthorizedException(NO_ACCESS_TO_REP_MSG);
}
try {
return repo.getKeys(getBareJID(), subnode);
} catch (UserNotFoundException e) {
log.log(Level.FINEST, "Problem accessing reposiotry: ", e);
throw new NotAuthorizedException(NO_ACCESS_TO_REP_MSG, e);
// } catch (TigaseDBException e) {
// log.log(Level.SEVERE, "Repository access exception.", e);
} // end of try-catch
// return null;
}
/**
* This method allows to retrieve list of values associated with one key. As
* it is possible to store many values with one key there are a few methods
* which provides this functionality. If given key does not exists in given
* subnode <code>null</code> is returned.
*
* @param subnode
* a <code>String</code> value pointing to specific subnode in user
* reposiotry where data have to be stored.
* @param key
* a <code>String</code> value of data key ID.
* @return a <code>String[]</code> array containing all values found for given
* key.
* @exception NotAuthorizedException
* is thrown when session has not been authorized yet and there
* is no access to permanent storage.
* @throws TigaseDBException
* @see #setData(String, String, String)
*/
public String[] getDataList(String subnode, String key) throws NotAuthorizedException,
TigaseDBException {
if (is_anonymous) {
return null;
}
if (!isAuthorized()) {
throw new NotAuthorizedException(NO_ACCESS_TO_REP_MSG);
}
try {
return repo.getDataList(getBareJID(), subnode, key);
} catch (UserNotFoundException e) {
log.log(Level.FINEST, "Problem accessing reposiotry: ", e);
throw new NotAuthorizedException(NO_ACCESS_TO_REP_MSG, e);
// } catch (TigaseDBException e) {
// log.log(Level.SEVERE, "Repository access exception.", e);
} // end of try-catch
// return null;
}
/**
* Method description
*
*
* @return
*/
public VHostItem getDomain() {
return domain;
}
/**
* Method description
*
*
* @return
*/
public JID getDomainAsJID() {
return domain.getVhost();
}
/**
* Method description
*
*
* @param subnode
* @param key
* @param def
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public String getOfflineData(String subnode, String key, String def)
throws NotAuthorizedException, TigaseDBException {
return getData(calcNode(OFFLINE_DATA_NODE, subnode), key, def);
}
/**
* Method description
*
*
* @param subnode
* @param key
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public String[] getOfflineDataList(String subnode, String key)
throws NotAuthorizedException, TigaseDBException {
return getDataList(calcNode(OFFLINE_DATA_NODE, subnode), key);
}
/**
* Method description
*
*
* @param subnode
* @param key
* @param def
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public String getPublicData(String subnode, String key, String def)
throws NotAuthorizedException, TigaseDBException {
return getData(calcNode(PUBLIC_DATA_NODE, subnode), key, def);
}
/**
* Method description
*
*
* @param subnode
* @param key
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public String[] getPublicDataList(String subnode, String key)
throws NotAuthorizedException, TigaseDBException {
return getDataList(calcNode(PUBLIC_DATA_NODE, subnode), key);
}
/**
* Method description
*
*
* @return
*/
public boolean isAnonymous() {
return is_anonymous;
}
// /**
// * Sets the value of authState
// *
// * @param argAuthState Value to assign to this.authState
// */
// protected void setAuthState(final Authorization argAuthState) {
// this.authState = argAuthState;
// }
/**
* This method allows you test this session if it already has been authorized.
* If <code>true</code> is returned as method result it means session has
* already been authorized, if <code>false</code> however session is still not
* authorized.
*
* @return a <code>boolean</code> value which informs whether this session has
* been already authorized or not.
*/
public boolean isAuthorized() {
return authState == Authorization.AUTHORIZED;
}
// ~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param userId
* @param digest
* @param id
* @param alg
*
* @return
*
* @throws AuthorizationException
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
@Deprecated
public Authorization loginDigest(BareJID userId, String digest, String id, String alg)
throws NotAuthorizedException, AuthorizationException, TigaseDBException {
isLoginAllowed();
try {
if (authRepo.digestAuth(userId, digest, id, alg)) {
authState = Authorization.AUTHORIZED;
login();
} // end of if (authRepo.loginPlain())auth.login();
return authState;
} catch (UserNotFoundException e) {
log.log(Level.FINEST, "Problem accessing reposiotry: ", e);
throw new NotAuthorizedException("Authorization failed", e);
// } catch (TigaseDBException e) {
// log.log(Level.SEVERE, "Repository access exception.", e);
// throw new NotAuthorizedException("Authorization failed", e);
} // end of try-catch
}
/**
* Method description
*
*
* @param props
*
* @return
*
* @throws AuthorizationException
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public Authorization loginOther(Map<String, Object> props)
throws NotAuthorizedException, AuthorizationException, TigaseDBException {
isLoginAllowed();
try {
String mech = (String) props.get(AuthRepository.MACHANISM_KEY);
if (domain.isAnonymousEnabled() && (mech != null) && mech.equals(ANONYMOUS_MECH)) {
is_anonymous = true;
props.put(AuthRepository.USER_ID_KEY, BareJID.bareJIDInstanceNS(UUID.randomUUID()
.toString(), getDomain().getVhost().getDomain()));
authState = Authorization.AUTHORIZED;
login();
} else {
if (authRepo.otherAuth(props)) {
authState = Authorization.AUTHORIZED;
login();
} // end of if (authRepo.loginPlain())auth.login();
}
return authState;
} catch (UserNotFoundException e) {
log.log(Level.FINEST, "User not found: ", e);
throw new NotAuthorizedException("Authorization failed", e);
// } catch (TigaseDBException e) {
// log.log(Level.SEVERE, "Repository access exception.", e);
// throw new NotAuthorizedException("Authorization failed", e);
} // end of try-catch
}
/**
* <code>authorize</code> method performs authorization with given password as
* plain text. If <code>AUTHORIZED</code> has been returned it means
* authorization process is successful and session has been activated,
* otherwise session hasn't been authorized and return code gives more
* detailed information of fail reason. Please refer to
* <code>Authorization</code> documentation for more details.
*
* @param userId
* @param password
* @return a <code>Authorization</code> value of result code.
* @throws NotAuthorizedException
* @throws AuthorizationException
* @throws TigaseDBException
*/
@Deprecated
public Authorization loginPlain(BareJID userId, String password)
throws NotAuthorizedException, AuthorizationException, TigaseDBException {
isLoginAllowed();
try {
if (authRepo.plainAuth(userId, password)) {
authState = Authorization.AUTHORIZED;
login();
} // end of if (authRepo.loginPlain())auth.login();
return authState;
} catch (UserNotFoundException e) {
log.info("User not found, authorization failed: " + userId);
throw new NotAuthorizedException("Authorization failed", e);
// } catch (TigaseDBException e) {
// log.log(Level.SEVERE, "Repository access exception.", e);
// throw new NotAuthorizedException("Authorization failed", e);
} // end of try-catch
}
/**
* Method description
*
*
* @param userId
* @param xmpp_sessionId
* @param token
*
* @return
*
*
* @throws AuthorizationException
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public Authorization loginToken(BareJID userId, String xmpp_sessionId, String token)
throws NotAuthorizedException, AuthorizationException, TigaseDBException {
isLoginAllowed();
try {
String db_token = repo.getData(userId, "tokens", xmpp_sessionId);
if (token.equals(db_token)) {
authState = Authorization.AUTHORIZED;
login();
repo.removeData(userId, "tokens", xmpp_sessionId);
}
} catch (UserNotFoundException e) {
log.log(Level.FINEST, "Problem accessing reposiotry: ", e);
throw new NotAuthorizedException(NO_ACCESS_TO_REP_MSG, e);
// } catch (TigaseDBException e) {
// log.log(Level.SEVERE, "Repository access exception.", e);
} // end of try-catch
return authState;
}
/**
* Method description
*
*
* @throws NotAuthorizedException
*/
public void logout() throws NotAuthorizedException {
authState = Authorization.NOT_AUTHORIZED;
}
/**
* Method description
*
*
* @param authProps
* @throws TigaseDBException
*/
public void queryAuth(Map<String, Object> authProps) throws TigaseDBException {
if (authRepo == null) {
log.severe("Authentication repository is not available! Misconfiguration error or "
+ "authentication database is not available. Please check your logs from the "
+ "server startup time.");
return;
}
authProps.put(AuthRepository.SERVER_NAME_KEY, getDomain().getVhost().getDomain());
authRepo.queryAuth(authProps);
if (domain.isAnonymousEnabled()
&& (authProps.get(AuthRepository.PROTOCOL_KEY) == AuthRepository.PROTOCOL_VAL_SASL)) {
String[] auth_mechs = (String[]) authProps.get(AuthRepository.RESULT_KEY);
if (auth_mechs == null) {
throw new TigaseDBException("No euthentication mechanisms found, probably "
+ "DB misconfiguration problem.");
}
auth_mechs = Arrays.copyOf(auth_mechs, auth_mechs.length + 1);
auth_mechs[auth_mechs.length - 1] = ANONYMOUS_MECH;
authProps.put(AuthRepository.RESULT_KEY, auth_mechs);
}
}
/**
* Method description
*
*
* @param name_param
* @param pass_param
* @param email_param
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
* @throws TigaseStringprepException
*
* @deprecated
*/
@Deprecated
public Authorization register(String name_param, String pass_param, String email_param)
throws NotAuthorizedException, TigaseDBException, TigaseStringprepException {
Map<String, String> reg_params = null;
if ((email_param != null) && !email_param.trim().isEmpty()) {
reg_params = new LinkedHashMap<String, String>();
reg_params.put("email", email_param);
}
return register(name_param, pass_param, reg_params);
}
/**
* Method description
*
*
* @param name_param
* @param pass_param
* @param reg_params
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
* @throws TigaseStringprepException
*/
public Authorization register(String name_param, String pass_param,
Map<String, String> reg_params) throws NotAuthorizedException, TigaseDBException,
TigaseStringprepException {
// Some clients send plain user name and others send
// jid as user name. Let's resolve this here.
String user_name = BareJID.parseJID(name_param)[0];
if ((user_name == null) || user_name.trim().isEmpty()) {
user_name = name_param;
} // end of if (user_mame == null || user_name.equals(""))
if (isAuthorized()) {
return changeRegistration(user_name, pass_param, reg_params);
}
// new user registration, let's check limits...
if (!domain.isRegisterEnabled()) {
throw new NotAuthorizedException("Registration is now allowed for this domain");
}
if (domain.getMaxUsersNumber() > 0) {
long domainUsers = authRepo.getUsersCount(domain.getVhost().getDomain());
if (log.isLoggable(Level.FINEST)) {
log.finest("Current number of users for domain: " + domain.getVhost().getDomain()
+ " is: " + domainUsers);
}
if (domainUsers >= domain.getMaxUsersNumber()) {
throw new NotAuthorizedException("Maximum users number for the domain exceeded.");
}
}
if ((user_name == null) || user_name.equals("") || (pass_param == null)
|| pass_param.equals("")) {
return Authorization.NOT_ACCEPTABLE;
}
try {
authRepo.addUser(
BareJID.bareJIDInstance(user_name, getDomain().getVhost().getDomain()),
pass_param);
if (log.isLoggable(Level.INFO)) {
log.info("User added: "
+ BareJID.toString(user_name, getDomain().getVhost().getDomain())
+ ", pass: " + pass_param);
}
setRegistration(user_name, pass_param, reg_params);
if (log.isLoggable(Level.INFO)) {
log.info("Registration data set for: "
+ BareJID.toString(user_name, getDomain().getVhost().getDomain())
+ ", pass: " + pass_param + ", reg_params: " + reg_params);
}
return Authorization.AUTHORIZED;
} catch (UserExistsException e) {
return Authorization.CONFLICT;
} catch (TigaseDBException e) {
log.log(Level.SEVERE, "Repository access exception.", e);
return Authorization.INTERNAL_SERVER_ERROR;
} // end of try-catch
}
/**
* Method description
*
*
* @param subnode
* @param key
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public void removeData(String subnode, String key) throws NotAuthorizedException,
TigaseDBException {
try {
repo.removeData(getBareJID(), subnode, key);
} catch (UserNotFoundException e) {
log.log(Level.FINEST, "Problem accessing reposiotry: ", e);
throw new NotAuthorizedException(NO_ACCESS_TO_REP_MSG, e);
// } catch (TigaseDBException e) {
// log.log(Level.SEVERE, "Repository access exception.", e);
} // end of try-catch
}
/**
* Removes the last data node given in subnode path as parameter to this
* method. All subnodes are moved as well an all data stored as
* <code>(key, val)</code> are removed as well. Changes are commited to
* repository immediatelly and there is no way to undo this operation so use
* it with care.
*
* @param subnode
* a <code>String</code> value of path to node which has to be
* removed.
* @exception NotAuthorizedException
* is thrown when session has not been authorized yet and there
* is no access to permanent storage.
* @throws TigaseDBException
* @see #setData(String, String, String)
*/
public void removeDataGroup(final String subnode) throws NotAuthorizedException,
TigaseDBException {
if (is_anonymous) {
return;
}
if (!isAuthorized()) {
throw new NotAuthorizedException(NO_ACCESS_TO_REP_MSG);
}
try {
repo.removeSubnode(getBareJID(), subnode);
} catch (UserNotFoundException e) {
log.log(Level.FINEST, "Problem accessing reposiotry: ", e);
throw new NotAuthorizedException(NO_ACCESS_TO_REP_MSG, e);
// } catch (TigaseDBException e) {
// log.log(Level.SEVERE, "Repository access exception.", e);
} // end of try-catch
}
/**
* Method description
*
*
* @param subnode
* @param key
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public void removeOfflineData(String subnode, String key)
throws NotAuthorizedException, TigaseDBException {
removeData(calcNode(OFFLINE_DATA_NODE, subnode), key);
}
/**
* Method description
*
*
* @param subnode
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public void removeOfflineDataGroup(String subnode) throws NotAuthorizedException,
TigaseDBException {
removeDataGroup(calcNode(OFFLINE_DATA_NODE, subnode));
}
/**
* Method description
*
*
* @param subnode
* @param key
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public void removePublicData(String subnode, String key) throws NotAuthorizedException,
TigaseDBException {
removeData(calcNode(PUBLIC_DATA_NODE, subnode), key);
}
/**
* Method description
*
*
* @param subnode
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public void removePublicDataGroup(String subnode) throws NotAuthorizedException,
TigaseDBException {
removeDataGroup(calcNode(PUBLIC_DATA_NODE, subnode));
}
// ~--- set methods ----------------------------------------------------------
/**
* This method stores given data in permanent storage in given point of
* hierarchy of data base. This method is similar to
* <code>setData(String, String)</code> and differs in one additional
* parameter which point to user data base subnode where data must be stored.
* It helps to organize user data in more logical hierarchy.<br/>
* User data is kind of tree where you can store data in each tree node. The
* most relevant sample might be structure like typical file system or XML
* like or LDAP data base. The first implementation is actually done as XML
* file to make it easier test application and deploy simple installation
* where there is no more users than 1000.<br/>
* To find out more about user repository refer to <code>UserRepository</code>
* interface for general info and to <code>XMLRepository</code> for detailed
* explanation regarding XML implementation of user repository.
* <p>
* Thus <code>subnode</code> is kind of path to data node. If you specify
* <code>null</code> or empty node data will be stored in root user node. This
* has exactly the same effect as you call
* <code>setData(String, String)</code>. If you want to store data in
* different node you must just specify node path like you do it to directory
* on most file systems:
*
* <pre>
* /roster
* </pre>
*
* Or, if you need access deeper node:
*
* <pre>
* /just/like/path/to/file
* </pre>
*
* </p>
* If given node does not yet exist it will be automaticaly created with all
* nodes in given path so there is no need for developer to perform additional
* action to create node. There is, however method
* <code>removeDataGroup(String)</code> for deleting specified node as nodes
* are not automaticaly deleted.
*
* @param subnode
* a <code>String</code> value pointing to specific subnode in user
* reposiotry where data have to be stored.
* @param key
* a <code>String</code> value of data key ID.
* @param value
* a <code>String</code> actual data stored in user repository.
* @exception NotAuthorizedException
* is thrown when session has not been authorized yet and there
* is no access to permanent storage.
* @throws TigaseDBException
* @see #removeDataGroup(String)
* @see UserRepository
*/
public void setData(String subnode, String key, String value)
throws NotAuthorizedException, TigaseDBException {
try {
repo.setData(getBareJID(), subnode, key, value);
} catch (UserNotFoundException e) {
log.log(Level.FINEST, "Problem accessing reposiotry: ", e);
throw new NotAuthorizedException(NO_ACCESS_TO_REP_MSG, e);
// } catch (TigaseDBException e) {
// log.log(Level.SEVERE, "Repository access exception.", e);
} // end of try-catch
}
/**
* This method allows to store list of values under one key ID reference. It
* is often necessary to keep set of values which can be refered by one key.
* As an example might be list of groups for specific buddy in roster. There
* is no actual need to store each group with separate key because we usually
* need to acces whole list of groups.
*
* @param subnode
* a <code>String</code> value pointing to specific subnode in user
* reposiotry where data have to be stored.
* @param key
* a <code>String</code> value of data key ID.
* @param list
* a <code>String[]</code> keeping list of actual data to be stored
* in user repository.
* @exception NotAuthorizedException
* is thrown when session has not been authorized yet and there
* is no access to permanent storage.
* @throws TigaseDBException
* @see #setData(String, String, String)
*/
public void setDataList(final String subnode, final String key, final String[] list)
throws NotAuthorizedException, TigaseDBException {
if (is_anonymous) {
return;
}
if (!isAuthorized()) {
throw new NotAuthorizedException(NO_ACCESS_TO_REP_MSG);
}
try {
repo.setDataList(getBareJID(), subnode, key, list);
} catch (UserNotFoundException e) {
log.log(Level.FINEST, "Problem accessing reposiotry: ", e);
throw new NotAuthorizedException(NO_ACCESS_TO_REP_MSG, e);
// } catch (TigaseDBException e) {
// log.log(Level.SEVERE, "Repository access exception.", e);
} // end of try-catch
}
/**
* Method description
*
*
* @param domain
*
* @throws TigaseStringprepException
*/
public void setDomain(final VHostItem domain) throws TigaseStringprepException {
this.domain = domain;
}
/**
* Method description
*
*
* @param subnode
* @param key
* @param value
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public void setOfflineData(String subnode, String key, String value)
throws NotAuthorizedException, TigaseDBException {
setData(calcNode(OFFLINE_DATA_NODE, subnode), key, value);
}
/**
* Method description
*
*
* @param subnode
* @param key
* @param list
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public void setOfflineDataList(String subnode, String key, String[] list)
throws NotAuthorizedException, TigaseDBException {
setDataList(calcNode(OFFLINE_DATA_NODE, subnode), key, list);
}
/**
* Method description
*
*
* @param subnode
* @param key
* @param value
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public void setPublicData(String subnode, String key, String value)
throws NotAuthorizedException, TigaseDBException {
setData(calcNode(PUBLIC_DATA_NODE, subnode), key, value);
}
/**
* Method description
*
*
* @param subnode
* @param key
* @param list
*
* @throws NotAuthorizedException
* @throws TigaseDBException
*/
public void setPublicDataList(String subnode, String key, String[] list)
throws NotAuthorizedException, TigaseDBException {
setDataList(calcNode(PUBLIC_DATA_NODE, subnode), key, list);
}
// ~--- methods --------------------------------------------------------------
/**
* Method description
*
*
* @param name_param
*
* @return
*
* @throws NotAuthorizedException
* @throws TigaseDBException
* @throws TigaseStringprepException
*/
public Authorization unregister(String name_param) throws NotAuthorizedException,
TigaseDBException, TigaseStringprepException {
if (!isAuthorized()) {
return Authorization.FORBIDDEN;
}
// Some clients send plain user name and others send
// jid as user name. Let's resolve this here.
String user_name = BareJID.parseJID(name_param)[0];
if ((user_name == null) || user_name.trim().isEmpty()) {
user_name = name_param;
} // end of if (user_mame == null || user_name.equals(""))
if (getUserName().equals(user_name)) {
try {
authRepo.removeUser(BareJID.bareJIDInstance(user_name, getDomain().getVhost()
.getDomain()));
try {
repo.removeUser(BareJID.bareJIDInstance(user_name, getDomain().getVhost()
.getDomain()));
} catch (UserNotFoundException ex) {
// We ignore this error here. If auth_repo and user_repo are in fact
// the same
// database, then user has been already removed with the
// auth_repo.removeUser(...)
// then the second call to user_repo may throw the exception which is
// fine.
}
// We mark the session as no longer authorized to prevent data access through
// this session.
logout();
// Session authorized is returned only to indicate successful operation.
return Authorization.AUTHORIZED;
} catch (UserNotFoundException e) {
return Authorization.REGISTRATION_REQUIRED;
} catch (TigaseDBException e) {
log.log(Level.SEVERE, "Repository access exception.", e);
return Authorization.INTERNAL_SERVER_ERROR;
} // end of catch
} else {
return Authorization.FORBIDDEN;
}
}
private String calcNode(String base, String subnode) {
if (subnode == null) {
return base;
} // end of if (subnode == null)
return base + "/" + subnode;
}
private Authorization changeRegistration(final String name_param,
final String pass_param, final Map<String, String> registr_params)
throws NotAuthorizedException, TigaseDBException, TigaseStringprepException {
if ((name_param == null) || name_param.equals("") || (pass_param == null)
|| pass_param.equals("")) {
return Authorization.BAD_REQUEST;
}
if (getUserName().equals(name_param)) {
setRegistration(name_param, pass_param, registr_params);
return Authorization.AUTHORIZED;
} else {
return Authorization.NOT_AUTHORIZED;
}
}
// ~--- get methods ----------------------------------------------------------
private boolean isLoginAllowed() throws AuthorizationException {
if (isAuthorized()) {
throw new AuthorizationException("User session already authenticated. "
+ "Subsequent login is forbidden. You must loggin on a different connection.");
}
return true;
}
// ~--- set methods ----------------------------------------------------------
private void setRegistration(final String name_param, final String pass_param,
final Map<String, String> registr_params) throws TigaseDBException,
TigaseStringprepException {
try {
authRepo.updatePassword(
BareJID.bareJIDInstance(name_param, getDomain().getVhost().getDomain()),
pass_param);
if (registr_params != null) {
for (Map.Entry<String, String> entry : registr_params.entrySet()) {
repo.setData(
BareJID.bareJIDInstance(name_param, getDomain().getVhost().getDomain()),
entry.getKey(), entry.getValue());
}
}
} catch (UserNotFoundException e) {
log.log(Level.WARNING, "Problem accessing reposiotry: ", e);
// } catch (TigaseDBException e) {
// log.log(Level.SEVERE, "Repository access exception.", e);
} // end of try-catch
}
} // RepositoryAccess
// ~ Formatted in Sun Code Convention
// ~ Formatted by Jindent --- http://www.jindent.com