/* * DBeaver - Universal Database Manager * Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org) * * 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.jkiss.dbeaver.ext.mysql.model; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.DBPRefreshableObject; import org.jkiss.dbeaver.model.DBPSaveableObject; import org.jkiss.dbeaver.model.DBUtils; import org.jkiss.dbeaver.model.access.DBAUser; import org.jkiss.dbeaver.model.exec.jdbc.JDBCPreparedStatement; import org.jkiss.dbeaver.model.exec.jdbc.JDBCResultSet; import org.jkiss.dbeaver.model.exec.jdbc.JDBCSession; import org.jkiss.dbeaver.model.impl.jdbc.JDBCUtils; import org.jkiss.dbeaver.model.meta.Property; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; import org.jkiss.dbeaver.model.struct.DBSObject; import org.jkiss.utils.CommonUtils; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.StringTokenizer; import java.util.regex.Matcher; /** * MySQLUser */ public class MySQLUser implements DBAUser, DBPRefreshableObject, DBPSaveableObject { private static final Log log = Log.getLog(MySQLUser.class); private MySQLDataSource dataSource; private String userName; private String host; private String passwordHash; private String sslType; private byte[] sslCipher; private byte[] x509Issuer; private byte[] x509Subject; private int maxQuestions; private int maxUpdates; private int maxConnections; private int maxUserConnections; private List<MySQLGrant> grants; private boolean persisted; public MySQLUser(MySQLDataSource dataSource, ResultSet resultSet) { this.dataSource = dataSource; if (resultSet != null) { this.persisted = true; this.userName = JDBCUtils.safeGetString(resultSet, "user"); this.host = JDBCUtils.safeGetString(resultSet, "host"); this.passwordHash = JDBCUtils.safeGetString(resultSet, "password"); this.sslType = JDBCUtils.safeGetString(resultSet, "ssl_type"); this.sslCipher = JDBCUtils.safeGetBytes(resultSet, "ssl_cipher"); this.x509Issuer = JDBCUtils.safeGetBytes(resultSet, "x509_issuer"); this.x509Subject = JDBCUtils.safeGetBytes(resultSet, "x509_subject"); this.maxQuestions = JDBCUtils.safeGetInt(resultSet, "max_questions"); this.maxUpdates = JDBCUtils.safeGetInt(resultSet, "max_updates"); this.maxConnections = JDBCUtils.safeGetInt(resultSet, "max_connections"); this.maxUserConnections = JDBCUtils.safeGetInt(resultSet, "max_user_connections"); } else { this.persisted = false; this.userName = "user"; this.host = "%"; } } @NotNull @Override @Property(viewable = true, order = 1) public String getName() { return userName + "@" + host; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getFullName() { return "'" + userName + "'@'" + host + "'"; } @Nullable @Override public String getDescription() { return null; } @Override public DBSObject getParentObject() { return dataSource.getContainer(); } @NotNull @Override public MySQLDataSource getDataSource() { return dataSource; } @Override public boolean isPersisted() { return persisted; } @Override public void setPersisted(boolean persisted) { this.persisted = persisted; DBUtils.fireObjectUpdate(this); } @Property(viewable = true, order = 2) public String getHost() { return host; } public void setHost(String host) { this.host = host; } public String getPasswordHash() { return passwordHash; } public void clearGrantsCache() { this.grants = null; } public List<MySQLGrant> getGrants(DBRProgressMonitor monitor) throws DBException { if (this.grants != null) { return this.grants; } if (!isPersisted()) { this.grants = new ArrayList<>(); return this.grants; } try (JDBCSession session = DBUtils.openMetaSession(monitor, getDataSource(), "Read catalog privileges")) { try (JDBCPreparedStatement dbStat = session.prepareStatement("SHOW GRANTS FOR " + getFullName())) { try (JDBCResultSet dbResult = dbStat.executeQuery()) { List<MySQLGrant> grants = new ArrayList<>(); while (dbResult.next()) { List<MySQLPrivilege> privileges = new ArrayList<>(); boolean allPrivilegesFlag = false; boolean grantOption = false; String catalog = null; String table = null; String grantString = CommonUtils.notEmpty(JDBCUtils.safeGetString(dbResult, 1)).trim().toUpperCase(Locale.ENGLISH); if (grantString.endsWith(" WITH GRANT OPTION")) { grantOption = true;//privileges.add(getDataSource().getPrivilege(monitor, MySQLPrivilege.GRANT_PRIVILEGE)); } String privString; Matcher matcher = MySQLGrant.TABLE_GRANT_PATTERN.matcher(grantString); if (matcher.find()) { privString = matcher.group(1); catalog = matcher.group(2); table = matcher.group(3); } else { matcher = MySQLGrant.GLOBAL_GRANT_PATTERN.matcher(grantString); if (matcher.find()) { privString = matcher.group(1); } else { log.warn("Can't parse GRANT string: " + grantString); continue; } } StringTokenizer st = new StringTokenizer(privString, ","); while (st.hasMoreTokens()) { String privName = st.nextToken().trim(); if (privName.equalsIgnoreCase(MySQLPrivilege.ALL_PRIVILEGES)) { allPrivilegesFlag = true; continue; } MySQLPrivilege priv = getDataSource().getPrivilege(monitor, privName); if (priv == null) { log.warn("Can't find privilege '" + privName + "'"); } else { privileges.add(priv); } } grants.add( new MySQLGrant( this, privileges, catalog, table, allPrivilegesFlag, grantOption)); } this.grants = grants; return this.grants; } } } catch (SQLException e) { throw new DBException(e, getDataSource()); } } public String getSslType() { return sslType; } void setSslType(String sslType) { this.sslType = sslType; } public byte[] getSslCipher() { return sslCipher; } void setSslCipher(byte[] sslCipher) { this.sslCipher = sslCipher; } public byte[] getX509Issuer() { return x509Issuer; } void setX509Issuer(byte[] x509Issuer) { this.x509Issuer = x509Issuer; } public byte[] getX509Subject() { return x509Subject; } void setX509Subject(byte[] x509Subject) { this.x509Subject = x509Subject; } public int getMaxQuestions() { return maxQuestions; } public void setMaxQuestions(int maxQuestions) { this.maxQuestions = maxQuestions; } public int getMaxUpdates() { return maxUpdates; } public void setMaxUpdates(int maxUpdates) { this.maxUpdates = maxUpdates; } public int getMaxConnections() { return maxConnections; } public void setMaxConnections(int maxConnections) { this.maxConnections = maxConnections; } public int getMaxUserConnections() { return maxUserConnections; } public void setMaxUserConnections(int maxUserConnections) { this.maxUserConnections = maxUserConnections; } @Override public DBSObject refreshObject(@NotNull DBRProgressMonitor monitor) throws DBException { grants = null; return this; } }