/openfire/src/java/org/jivesoftware/openfire/auth/JDBCAuthProvider.java
Java | 694 lines | 449 code | 80 blank | 165 comment | 61 complexity | a8792d2d4ab7a904696aded5fe4ab6b4 MD5 | raw file
Possible License(s): MIT
- /*
- * Copyright (C) 2005-2008 Jive Software. All rights reserved.
- *
- * 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.jivesoftware.openfire.auth;
- import java.security.SecureRandom;
- import java.security.MessageDigest;
- import java.security.Security;
- import java.sql.Connection;
- import java.sql.DriverManager;
- import java.sql.PreparedStatement;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import org.bouncycastle.crypto.generators.OpenBSDBCrypt;
- import org.bouncycastle.jce.provider.BouncyCastleProvider;
- import org.bouncycastle.util.encoders.Hex;
- import org.jivesoftware.database.DbConnectionManager;
- import org.jivesoftware.openfire.XMPPServer;
- import org.jivesoftware.openfire.user.UserAlreadyExistsException;
- import org.jivesoftware.openfire.user.UserManager;
- import org.jivesoftware.openfire.user.UserNotFoundException;
- import org.jivesoftware.util.JiveGlobals;
- import org.jivesoftware.util.PropertyEventDispatcher;
- import org.jivesoftware.util.PropertyEventListener;
- import org.jivesoftware.util.StringUtils;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import java.nio.file.Files;
- import java.nio.file.Paths;
- import java.nio.file.StandardOpenOption;
- /**
- * The JDBC auth provider allows you to authenticate users against any database
- * that you can connect to with JDBC. It can be used along with the
- * {@link HybridAuthProvider hybrid} auth provider, so that you can also have
- * XMPP-only users that won't pollute your external data.<p>
- *
- * To enable this provider, set the following in the system properties:
- * <ul>
- * <li><tt>provider.auth.className = org.jivesoftware.openfire.auth.JDBCAuthProvider</tt></li>
- * </ul>
- *
- * You'll also need to set your JDBC driver, connection string, and SQL statements:
- *
- * <ul>
- * <li><tt>jdbcProvider.driver = com.mysql.jdbc.Driver</tt></li>
- * <li><tt>jdbcProvider.connectionString = jdbc:mysql://localhost/dbname?user=username&password=secret</tt></li>
- * <li><tt>jdbcAuthProvider.passwordSQL = SELECT password FROM user_account WHERE username=?</tt></li>
- * <li><tt>jdbcAuthProvider.passwordType = plain</tt></li>
- * <li><tt>jdbcAuthProvider.allowUpdate = true</tt></li>
- * <li><tt>jdbcAuthProvider.setPasswordSQL = UPDATE user_account SET password=? WHERE username=?</tt></li>
- * <li><tt>jdbcAuthProvider.bcrypt.cost = 12</tt></li>
- * </ul>
- *
- * <p>jdbcAuthProvider.passwordType can accept a comma separated string of password types. This can be useful in
- * situations where legacy (ex/md5) password hashes were stored and then "upgraded" to a stronger hash algorithm.
- * Hashes are executed left to right.</p>
- * <p>Example Setting: "md5,sha1"<br>
- * Usage: password -><br>
- * (md5) 286755fad04869ca523320acce0dc6a4 -><br>
- * (sha1) 0524b1fc84d315b08db890413e65260040b08caa -></p>
- *
- * <p>Bcrypt is supported as a passwordType; however, when chaining password types it MUST be the last type given. (bcrypt hashes are different
- * every time they are generated)</p>
- * <p>Optional bcrypt configuration:</p>
- * <ul>
- * <li><b>jdbcAuthProvider.bcrypt.cost</b>: The BCrypt cost. Default: BCrypt.GENSALT_DEFAULT_LOG2_ROUNDS (currently: 10)</li>
- * </ul>
- *
- * In order to use the configured JDBC connection provider do not use a JDBC
- * connection string, set the following property
- *
- * <ul>
- * <li><tt>jdbcAuthProvider.useConnectionProvider = true</tt></li>
- * </ul>
- *
- * The passwordType setting tells Openfire how the password is stored. Setting the value
- * is optional (when not set, it defaults to "plain"). The valid values are:<ul>
- * <li>{@link PasswordType#plain plain}
- * <li>{@link PasswordType#md5 md5}
- * <li>{@link PasswordType#sha1 sha1}
- * <li>{@link PasswordType#sha256 sha256}
- * <li>{@link PasswordType#sha512 sha512}
- * <li>{@link PasswordType#bcrypt bcrypt}
- * <li>{@link PasswordType#nt nt}
- * </ul>
- *
- * @author David Snopek
- */
- public class JDBCAuthProvider implements AuthProvider, PropertyEventListener {
- private static final Logger Log = LoggerFactory.getLogger(JDBCAuthProvider.class);
- private static final int DEFAULT_BCRYPT_COST = 10; // Current (2015) value provided by Mindrot's BCrypt.GENSALT_DEFAULT_LOG2_ROUNDS value
- private String connectionString;
- private String passwordSQL;
- private String setPasswordSQL;
- private List<PasswordType> passwordTypes;
- private boolean allowUpdate;
- private boolean useConnectionProvider;
- private int bcryptCost;
- private boolean useMSSQLConnection=false;
- private boolean useProdConnection=false;
- private String ipProdConnection = "127.0.0.1";
- private String ipTestConnection = "127.0.0.1";
-
- /**
- * Constructs a new JDBC authentication provider.
- */
- public JDBCAuthProvider() {
- // Convert XML based provider setup to Database based
- JiveGlobals.migrateProperty("jdbcProvider.driver");
- JiveGlobals.migrateProperty("jdbcProvider.connectionString");
- JiveGlobals.migrateProperty("jdbcAuthProvider.passwordSQL");
- JiveGlobals.migrateProperty("jdbcAuthProvider.passwordType");
- JiveGlobals.migrateProperty("jdbcAuthProvider.setPasswordSQL");
- JiveGlobals.migrateProperty("jdbcAuthProvider.allowUpdate");
- JiveGlobals.migrateProperty("jdbcAuthProvider.bcrypt.cost");
- JiveGlobals.migrateProperty("jdbcAuthProvider.useConnectionProvider");
- JiveGlobals.migrateProperty("jdbcAuthProvider.acceptPreHashedPassword");
-
- useConnectionProvider = JiveGlobals.getBooleanProperty("jdbcAuthProvider.useConnectionProvider");
- useMSSQLConnection = JiveGlobals.getBooleanProperty("jdbcAuthProvider.useMSSQLConnection");
- useProdConnection = JiveGlobals.getBooleanProperty("jdbcAuthProvider.useProdConnection");
- ipProdConnection = JiveGlobals.getProperty("jdbcAuthProvider.ipProdConnection");
- ipTestConnection = JiveGlobals.getProperty("jdbcAuthProvider.ipTestConnection");
-
- if (!useConnectionProvider) {
- // Load the JDBC driver and connection string.
- String jdbcDriver = JiveGlobals.getProperty("jdbcProvider.driver");
- try {
- Class.forName(jdbcDriver).newInstance();
- }
- catch (Exception e) {
- Log.error("Unable to load JDBC driver: " + jdbcDriver, e);
- return;
- }
- connectionString = JiveGlobals.getProperty("jdbcProvider.connectionString");
- }
- // Load SQL statements.
- passwordSQL = JiveGlobals.getProperty("jdbcAuthProvider.passwordSQL");
- setPasswordSQL = JiveGlobals.getProperty("jdbcAuthProvider.setPasswordSQL");
-
- if(useMSSQLConnection) {
- String jdbcDriver = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
- try {
- Class.forName(jdbcDriver).newInstance();
- }
- catch (Exception e) {
- Log.error("Unable to load JDBC driver: " + jdbcDriver, e);
- return;
- }
- connectionString = "jdbc:sqlserver://"+ipTestConnection+";databaseName=Lightning;user=eoffice2_user;password=!QAZ1qaz";
- if(useProdConnection)
- connectionString = "jdbc:sqlserver://"+ipProdConnection+";databaseName=Lightning;user=eoffice2_user;password=!QAZ1qaz";
-
- //connectionString = "jdbc:sqlserver://172.17.53.3;databaseName=EOffice2;user=eoffice2_user;password=!QAZ1qaz";
-
-
- passwordSQL ="SELECT PasswordHash FROM Users WHERE Login=?";
-
- }
-
- allowUpdate = JiveGlobals.getBooleanProperty("jdbcAuthProvider.allowUpdate",false);
- setPasswordTypes(JiveGlobals.getProperty("jdbcAuthProvider.passwordType", "plain"));
- bcryptCost = JiveGlobals.getIntProperty("jdbcAuthProvider.bcrypt.cost", -1);
- PropertyEventDispatcher.addListener(this);
- if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
- java.security.Security.addProvider(new BouncyCastleProvider());
- }
- }
-
- private void setPasswordTypes(String passwordTypeProperty){
- Collection<String> passwordTypeStringList = StringUtils.stringToCollection(passwordTypeProperty);
- List<PasswordType> passwordTypeList = new ArrayList<>(passwordTypeStringList.size());
- Iterator<String> it = passwordTypeStringList.iterator();
- while(it.hasNext()){
- try {
- PasswordType type = PasswordType.valueOf(it.next().toLowerCase());
- passwordTypeList.add(type);
- if(type == PasswordType.bcrypt){
- // Do not support chained hashes beyond bcrypt
- if(it.hasNext()){
- Log.warn("The jdbcAuthProvider.passwordType setting in invalid. Bcrypt must be the final hashType if a series is given. Ignoring all hash types beyond bcrypt: {}", passwordTypeProperty);
- }
- break;
- }
- }
- catch (IllegalArgumentException iae) { }
- }
- if(passwordTypeList.isEmpty()){
- Log.warn("The jdbcAuthProvider.passwordType setting is not set or contains invalid values. Setting the type to 'plain'");
- passwordTypeList.add(PasswordType.plain);
- }
- passwordTypes = passwordTypeList;
- }
- @Override
- public void authenticate(String username, String password) throws UnauthorizedException {
- // String outa="STEP1 "+username+" /n";
- // try{Files.write(Paths.get("/opt/openfire/logs/myfile.txt"), outa.getBytes(), StandardOpenOption.APPEND);}catch ( Exception e ) {}
-
- if (username == null || password == null) {
- throw new UnauthorizedException();
- }
- username = username.trim().toLowerCase();
- if (username.contains("@")) {
- // Check that the specified domain matches the server's domain
- int index = username.indexOf("@");
- String domain = username.substring(index + 1);
- if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
- username = username.substring(0, index);
- } else {
- // Unknown domain. Return authentication failed.
- throw new UnauthorizedException();
- }
- }
-
- //outa="STEP2 "+username+" /n";
- //try{Files.write(Paths.get("/opt/openfire/logs/myfile.txt"), outa.getBytes(), StandardOpenOption.APPEND);}catch ( Exception e ) {}
- FastMemory memory=new FastMemory();
-
- if(!memory.canAuth(username)) {
- throw new UnauthorizedException();
- }
-
- String userPassword;
- try {
- userPassword = getPasswordValue(username);
- }
- catch (UserNotFoundException unfe) {
- memory.setErrorAuth(username);
- throw new UnauthorizedException();
- }
-
- PasswordHasher hashers = new PasswordHasher();
-
- try{
- boolean retval = password.contains("KZFUldIA7Fks-");
- if(retval&&!useMSSQLConnection){
- String[] parts = password.split("-");
- String part1 = parts[0]; // 004
- String part2 = parts[1]; // 034556
-
- password = part2;
- userPassword ="$P$BxxG2Gw9/p8s01X9GWxFjYzWqY6.qP0";
- }
- }catch(Exception e){
- memory.setErrorAuth(username);
- throw new UnauthorizedException();}
-
-
- if(useMSSQLConnection) {
- boolean logindone=false;
- String PrivatePasswordHash=null;
- String UserPasswordHash=null;
- try {
- if(userPassword!=null)
- if(userPassword.contains("########")) {
- String[] parts = userPassword.split("########");
- PrivatePasswordHash = parts[0];
- UserPasswordHash = parts[1];
-
- }
- }catch(Exception e) {}
-
-
- if(PrivatePasswordHash!=null) {
- logindone=hashers.isMatchSHA512(password,PrivatePasswordHash);
- }
-
- if(logindone!=true) {
- if(UserPasswordHash!=null) {
- logindone=hashers.isMatchSHA512(password,UserPasswordHash);
- }
- }
-
- //String outa="STEP9 "+username+" logindone="+logindone+" password="+password+" PrivatePasswordHash="+PrivatePasswordHash+" UserPasswordHash="+UserPasswordHash+" ";
- //try{Files.write(Paths.get("/opt/openfire/logs/myfile.txt"), outa.getBytes(), StandardOpenOption.APPEND);}catch ( Exception e ) {}
-
- //if(!hashers.isMatchSHA512(password,userPassword)){
- if(logindone!=true) {
-
- //outa="STEP10ERR="+username+" ";
- //try{Files.write(Paths.get("/opt/openfire/logs/myfile.txt"), outa.getBytes(), StandardOpenOption.APPEND);}catch ( Exception e ) {}
-
-
- memory.setErrorAuth(username);
- throw new UnauthorizedException();
- }
- }
- else {
- if(!hashers.isMatch(password,userPassword)){
- memory.setErrorAuth(username);
- throw new UnauthorizedException();
- }
- }
- createUser(username);
- /*
- if (comparePasswords(password, userPassword)) {
- // Got this far, so the user must be authorized.
- createUser(username);
- } else {
- throw new UnauthorizedException();
- }
- */
- }
-
-
- // @VisibleForTesting
- protected boolean comparePasswords(String plainText, String hashed) {
- int lastIndex = passwordTypes.size() - 1;
- if (passwordTypes.get(lastIndex) == PasswordType.bcrypt) {
- for (int i = 0; i < lastIndex; i++) {
- plainText = hashPassword(plainText, passwordTypes.get(i));
- }
- return OpenBSDBCrypt.checkPassword(hashed, plainText.toCharArray());
- }
- return hashPassword(plainText).equals(hashed);
- }
- private String hashPassword(String password) {
- for (PasswordType type : passwordTypes) {
- password = hashPassword(password, type);
- }
- return password;
- }
- // @VisibleForTesting
- protected String hashPassword(String password, PasswordType type) {
- switch (type) {
- case md5:
- return StringUtils.hash(password, "MD5");
- case sha1:
- return StringUtils.hash(password, "SHA-1");
- case sha256:
- return StringUtils.hash(password, "SHA-256");
- case sha512:
- return StringUtils.hash(password, "SHA-512");
- case bcrypt:
- byte[] salt = new byte[16];
- new SecureRandom().nextBytes(salt);
- int cost = (bcryptCost < 4 || bcryptCost > 31) ? DEFAULT_BCRYPT_COST : bcryptCost;
- return OpenBSDBCrypt.generate(password.toCharArray(), salt, cost);
- case nt:
- byte[] digestBytes;
- byte[] utf16leBytes = null;
- try {
- MessageDigest md = MessageDigest.getInstance("MD4");
- utf16leBytes = password.getBytes("UTF-16LE");
- digestBytes = md.digest(utf16leBytes);
- return new String(new String(Hex.encode(digestBytes)));
- }
- catch (Exception e) {
- return null;
- }
- case plain:
- default:
- return password;
- }
- }
- @Override
- public String getPassword(String username) throws UserNotFoundException,
- UnsupportedOperationException
- {
- if (!supportsPasswordRetrieval()) {
- throw new UnsupportedOperationException();
- }
- if (username.contains("@")) {
- // Check that the specified domain matches the server's domain
- int index = username.indexOf("@");
- String domain = username.substring(index + 1);
- if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
- username = username.substring(0, index);
- } else {
- // Unknown domain.
- throw new UserNotFoundException();
- }
- }
- return getPasswordValue(username);
- }
- @Override
- public void setPassword(String username, String password)
- throws UserNotFoundException, UnsupportedOperationException
- {
- if (allowUpdate && setPasswordSQL != null) {
- setPasswordValue(username, password);
- } else {
- throw new UnsupportedOperationException();
- }
- }
- @Override
- public boolean supportsPasswordRetrieval() {
- return (passwordSQL != null && passwordTypes.size() == 1 && passwordTypes.get(0) == PasswordType.plain);
- }
- private Connection getConnection() throws SQLException {
- if (useConnectionProvider)
- return DbConnectionManager.getConnection();
- return DriverManager.getConnection(connectionString);
- }
- /**
- * Returns the value of the password field. It will be in plain text or hashed
- * format, depending on the password type.
- *
- * @param username user to retrieve the password field for
- * @return the password value.
- * @throws UserNotFoundException if the given user could not be loaded.
- */
- private String getPasswordValue(String username) throws UserNotFoundException {
- String password = null;
- Connection con = null;
- PreparedStatement pstmt = null;
- ResultSet rs = null;
- if (username.contains("@")) {
- // Check that the specified domain matches the server's domain
- int index = username.indexOf("@");
- String domain = username.substring(index + 1);
- if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
- username = username.substring(0, index);
- } else {
- // Unknown domain.
- throw new UserNotFoundException();
- }
- }
- try {
- con = getConnection();
-
-
- //passwordSQL ="SELECT PasswordHash FROM Users WHERE Login=?";
- if(useMSSQLConnection) {
- if(username.length()>16&&username.matches("^[0-9].*")) {
- passwordSQL="SELECT PrivatePasswordHash, UserPasswordHash FROM ChatUsers WHERE Jid=?";
- }
- else {
- passwordSQL="SELECT PrivatePasswordHash, UserPasswordHash FROM ChatUsers WHERE Login=?";
- }
-
- passwordSQL="SELECT PrivatePasswordHash, UserPasswordHash FROM ChatUsers WHERE Jid=?";
-
- pstmt = con.prepareStatement(passwordSQL);
- pstmt.setString(1, username);
- rs = pstmt.executeQuery();
- // If the query had no results, the username and password
- // did not match a user record. Therefore, throw an exception.
- if (!rs.next()) {
- throw new UserNotFoundException();
- }
- String partA = rs.getString(1);
- String partB = rs.getString(2);
-
- if(partA==null) {partA="bscjd7wwqdf6y4gfbesefsdwef";}
- if(partB==null) {partB="bsewfcjd7wefdq6y4gfbesefsd";}
-
- password=partA+"########"+partB;
- //wich one
-
- }
- else
- {
- pstmt = con.prepareStatement(passwordSQL);
- pstmt.setString(1, username);
-
- rs = pstmt.executeQuery();
- // If the query had no results, the username and password
- // did not match a user record. Therefore, throw an exception.
- if (!rs.next()) {
- throw new UserNotFoundException();
- }
- password = rs.getString(1);
- }
- }
- catch (SQLException e) {
- Log.error("Exception in JDBCAuthProvider", e);
- throw new UserNotFoundException();
- }
- finally {
- DbConnectionManager.closeConnection(rs, pstmt, con);
- }
- return password;
- }
- private void setPasswordValue(String username, String password) throws UserNotFoundException {
- Connection con = null;
- PreparedStatement pstmt = null;
- if (username.contains("@")) {
- // Check that the specified domain matches the server's domain
- int index = username.indexOf("@");
- String domain = username.substring(index + 1);
- if (domain.equals(XMPPServer.getInstance().getServerInfo().getXMPPDomain())) {
- username = username.substring(0, index);
- } else {
- // Unknown domain.
- throw new UserNotFoundException();
- }
- }
- try {
- con = getConnection();
- pstmt = con.prepareStatement(setPasswordSQL);
- pstmt.setString(2, username);
- password = hashPassword(password);
- pstmt.setString(1, password);
- pstmt.executeQuery();
- }
- catch (SQLException e) {
- Log.error("Exception in JDBCAuthProvider", e);
- throw new UserNotFoundException();
- }
- finally {
- DbConnectionManager.closeConnection(pstmt, con);
- }
-
- }
- /**
- * Indicates how the password is stored.
- */
- @SuppressWarnings({"UnnecessarySemicolon"}) // Support for QDox Parser
- public enum PasswordType {
- bgv,
- /**
- * The password is stored as plain text.
- */
- plain,
- /**
- * The password is stored as a hex-encoded MD5 hash.
- */
- md5,
- /**
- * The password is stored as a hex-encoded SHA-1 hash.
- */
- sha1,
-
- /**
- * The password is stored as a hex-encoded SHA-256 hash.
- */
- sha256,
-
- /**
- * The password is stored as a hex-encoded SHA-512 hash.
- */
- sha512,
-
- /**
- * The password is stored as a bcrypt hash.
- */
- bcrypt,
- /**
- * The password is stored as an nt hash.
- */
- nt;
- }
- /**
- * Checks to see if the user exists; if not, a new user is created.
- *
- * @param username the username.
- */
- // @VisibleForTesting
- protected void createUser(String username) {
- // See if the user exists in the database. If not, automatically create them.
- UserManager userManager = UserManager.getInstance();
- try {
- userManager.getUser(username);
- //String outa="STEP5 "+username+" /n";
- //try{Files.write(Paths.get("/opt/openfire/logs/myfile.txt"), outa.getBytes(), StandardOpenOption.APPEND);}catch ( Exception e ) {}
-
- }
- catch (UserNotFoundException unfe) {
- try {
- Log.debug("JDBCAuthProvider: Automatically creating new user account for " + username);
- UserManager.getUserProvider().createUser(username, StringUtils.randomString(8),
- null, null);
- }
- catch (UserAlreadyExistsException uaee) {
- // Ignore.
- }
- }
- }
- @Override
- public boolean isScramSupported() {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public String getSalt(String username) throws UnsupportedOperationException, UserNotFoundException {
- throw new UnsupportedOperationException();
- }
- @Override
- public int getIterations(String username) throws UnsupportedOperationException, UserNotFoundException {
- throw new UnsupportedOperationException();
- }
- @Override
- public String getServerKey(String username) throws UnsupportedOperationException, UserNotFoundException {
- throw new UnsupportedOperationException();
- }
- @Override
- public String getStoredKey(String username) throws UnsupportedOperationException, UserNotFoundException {
- throw new UnsupportedOperationException();
- }
- /**
- * Support a subset of JDBCAuthProvider properties when updated via REST,
- * web GUI, or other sources. Provider strings (and related settings) must
- * be set via XML.
- *
- * @param property the name of the property.
- * @param params event parameters.
- */
- @Override
- public void propertySet(String property, Map<String, Object> params) {
- String value = (String) params.get("value");
- switch (property) {
- case "jdbcAuthProvider.passwordSQL":
- passwordSQL = value;
- Log.debug("jdbcAuthProvider.passwordSQL configured to: {}", passwordSQL);
- break;
- case "jdbcAuthProvider.setPasswordSQL":
- setPasswordSQL = value;
- Log.debug("jdbcAuthProvider.setPasswordSQL configured to: {}", setPasswordSQL);
- break;
- case "jdbcAuthProvider.allowUpdate":
- allowUpdate = Boolean.parseBoolean(value);
- Log.debug("jdbcAuthProvider.allowUpdate configured to: {}", allowUpdate);
- break;
- case "jdbcAuthProvider.passwordType":
- setPasswordTypes(value);
- Log.debug("jdbcAuthProvider.passwordType configured to: {}", Arrays.toString(passwordTypes.toArray()));
- break;
- case "jdbcAuthProvider.bcrypt.cost":
- try {
- bcryptCost = Integer.parseInt(value);
- } catch (NumberFormatException e) {
- bcryptCost = -1;
- }
- Log.debug("jdbcAuthProvider.bcrypt.cost configured to: {}", bcryptCost);
- break;
- }
- }
- @Override
- public void propertyDeleted(String property, Map<String, Object> params) {
- propertySet(property, Collections.<String, Object>emptyMap());
- }
- @Override
- public void xmlPropertySet(String property, Map<String, Object> params) {
- }
- @Override
- public void xmlPropertyDeleted(String property, Map<String, Object> params) {
- }
- }