/**
* Licensed to Apereo under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright ownership. Apereo
* licenses this file to you 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 the
* following location:
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>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.apereo.portal.security.provider;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apereo.portal.AuthorizationException;
import org.apereo.portal.jdbc.RDBMServices;
import org.apereo.portal.security.IPermission;
import org.apereo.portal.security.IPermissionStore;
import org.springframework.stereotype.Repository;
/**
* Reference implementation of IPermissionStore. Performs CRUD operations on the UP_Permission
* table.
*
*/
@Repository
public class RDBMPermissionImpl implements IPermissionStore {
private static final Log log = LogFactory.getLog(RDBMPermissionImpl.class);
// sql Strings:
private static String PERMISSION_TABLE = "UP_PERMISSION";
private static String OWNER_COLUMN = "OWNER";
private static String PRINCIPAL_TYPE_COLUMN = "PRINCIPAL_TYPE";
private static String PRINCIPAL_KEY_COLUMN = "PRINCIPAL_KEY";
private static String ACTIVITY_COLUMN = "ACTIVITY";
private static String TARGET_COLUMN = "TARGET";
private static String TYPE_COLUMN = "PERMISSION_TYPE";
private static String EFFECTIVE_COLUMN = "EFFECTIVE";
private static String EXPIRES_COLUMN = "EXPIRES";
private static String allPermissionColumnsSql;
private static String deletePermissionSql;
private static String findPermissionSql;
private static String insertPermissionSql;
private static String selectPermissionSql;
private static String updatePermissionSql;
public static String PRINCIPAL_SEPARATOR = ".";
/**
* Signifies that the principal is an {@see IEntityGroup}. The {@see IPermission} contract does
* not define a method like <code>setPrincipalType()</code>, but {@see RDBMPermissionImpl} (this
* class) <i>does</i> have a notion of principal type. Specify <code>
* (PRINCIPAL_TYPE_GROUP|PRINCIPAL_TYPE_USER)PRINCIPAL_SEPARATOR<principal.key></code> to
* {@see IPermission.setPrincipal} for use with {@see RDBMPermissionImpl}.
*/
public static int PRINCIPAL_TYPE_GROUP = 1;
/**
* Signifies that the principal is an {@see IPerson}. The {@see IPermission} contract does not
* define a method like <code>setPrincipalType()</code>, but {@see RDBMPermissionImpl} (this
* class) <i>does</i> have a notion of principal type. Specify <code>
* (PRINCIPAL_TYPE_GROUP|PRINCIPAL_TYPE_USER)PRINCIPAL_SEPARATOR<principal.key></code> to
* {@see IPermission.setPrincipal} for use with {@see RDBMPermissionImpl}.
*/
public static int PRINCIPAL_TYPE_PERSON = 2;
/**
* Add the IPermissions to the store.
*
* @param perms org.apereo.portal.security.IPermission[]
* @exception AuthorizationException - wraps an Exception specific to the store.
*/
public void add(IPermission[] perms) throws AuthorizationException {
if (perms.length > 0) {
try {
primAdd(perms);
} catch (Exception ex) {
log.error("Exception adding permissions " + perms, ex);
throw new AuthorizationException(ex);
}
}
}
/**
* Add the IPermission to the store.
*
* @param perm org.apereo.portal.security.IPermission
* @exception AuthorizationException - wraps an Exception specific to the store.
*/
public void add(IPermission perm) throws AuthorizationException {
Connection conn = null;
int rc = 0;
try {
conn = RDBMServices.getConnection();
String sQuery = getInsertPermissionSql();
PreparedStatement ps = conn.prepareStatement(sQuery);
try {
primAdd(perm, ps);
if (log.isDebugEnabled()) log.debug("RDBMPermissionImpl.add(): " + ps);
rc = ps.executeUpdate();
if (rc != 1) {
throw new AuthorizationException("Problem adding Permission " + perm);
}
} finally {
ps.close();
}
} catch (Exception ex) {
log.error("Exception adding permission [" + perm + "]", ex);
throw new AuthorizationException("Problem adding Permission " + perm);
} finally {
RDBMServices.releaseConnection(conn);
}
}
/**
* Delete the IPermissions from the store.
*
* @param perms org.apereo.portal.security.IPermission[]
* @exception AuthorizationException - wraps an Exception specific to the store.
*/
public void delete(IPermission[] perms) throws AuthorizationException {
if (perms.length > 0) {
try {
primDelete(perms);
} catch (Exception ex) {
log.error("Exception deleting permissions " + Arrays.toString(perms), ex);
throw new AuthorizationException(
"Exception deleting permissions " + Arrays.toString(perms), ex);
}
}
}
/**
* Delete a single IPermission from the store.
*
* @param perm org.apereo.portal.security.IPermission
* @exception AuthorizationException - wraps an Exception specific to the store.
*/
public void delete(IPermission perm) throws AuthorizationException {
Connection conn = null;
try {
conn = RDBMServices.getConnection();
String sQuery = getDeletePermissionSql();
PreparedStatement ps = conn.prepareStatement(sQuery);
try {
primDelete(perm, ps);
} finally {
ps.close();
}
} catch (Exception ex) {
log.error("Exception deleting permission [" + perm + "]", ex);
throw new AuthorizationException("Problem deleting Permission " + perm, ex);
} finally {
RDBMServices.releaseConnection(conn);
}
}
/** @return java.lang.String */
private static String getAllPermissionColumnsSql() {
if (allPermissionColumnsSql == null) {
StringBuffer sqlBuff = new StringBuffer(200);
sqlBuff.append(OWNER_COLUMN);
sqlBuff.append(", ");
sqlBuff.append(PRINCIPAL_TYPE_COLUMN);
sqlBuff.append(", ");
sqlBuff.append(PRINCIPAL_KEY_COLUMN);
sqlBuff.append(", ");
sqlBuff.append(ACTIVITY_COLUMN);
sqlBuff.append(", ");
sqlBuff.append(TARGET_COLUMN);
sqlBuff.append(", ");
sqlBuff.append(TYPE_COLUMN);
sqlBuff.append(", ");
sqlBuff.append(EFFECTIVE_COLUMN);
sqlBuff.append(", ");
sqlBuff.append(EXPIRES_COLUMN);
allPermissionColumnsSql = sqlBuff.toString();
}
return allPermissionColumnsSql;
}
/** @return java.lang.String */
private static String getDeletePermissionSql() {
if (deletePermissionSql == null) {
StringBuffer sqlBuff = new StringBuffer(200);
sqlBuff.append("DELETE FROM ");
sqlBuff.append(PERMISSION_TABLE);
sqlBuff.append(" WHERE ");
sqlBuff.append(OWNER_COLUMN);
sqlBuff.append(" = ? AND ");
sqlBuff.append(PRINCIPAL_TYPE_COLUMN);
sqlBuff.append(" = ? AND ");
sqlBuff.append(PRINCIPAL_KEY_COLUMN);
sqlBuff.append(" = ? AND ");
sqlBuff.append(ACTIVITY_COLUMN);
sqlBuff.append(" = ? AND ");
sqlBuff.append(TARGET_COLUMN);
sqlBuff.append(" = ? ");
deletePermissionSql = sqlBuff.toString();
}
return deletePermissionSql;
}
/**
* Insert the method's description here. Creation date: (11/6/01 5:19:57 PM)
*
* @return java.lang.String
*/
private static java.lang.String getFindPermissionSql() {
if (findPermissionSql == null) {
StringBuffer sqlBuff = new StringBuffer(getSelectPermissionSql());
sqlBuff.append("WHERE ");
sqlBuff.append(OWNER_COLUMN);
sqlBuff.append(" = ? AND ");
sqlBuff.append(PRINCIPAL_TYPE_COLUMN);
sqlBuff.append(" = ? AND ");
sqlBuff.append(PRINCIPAL_KEY_COLUMN);
sqlBuff.append(" = ? AND ");
sqlBuff.append(ACTIVITY_COLUMN);
sqlBuff.append(" = ? AND ");
sqlBuff.append(TARGET_COLUMN);
sqlBuff.append(" = ? ");
sqlBuff.append(TYPE_COLUMN);
sqlBuff.append(" = ? ");
findPermissionSql = sqlBuff.toString();
}
return findPermissionSql;
}
/** @return java.lang.String */
private static String getInsertPermissionSql() {
if (insertPermissionSql == null) {
StringBuffer sqlBuff = new StringBuffer(200);
sqlBuff.append("INSERT INTO ");
sqlBuff.append(PERMISSION_TABLE);
sqlBuff.append(" (");
sqlBuff.append(getAllPermissionColumnsSql());
sqlBuff.append(") VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
insertPermissionSql = sqlBuff.toString();
}
return insertPermissionSql;
}
/**
* Returns the principal key portion of the IPermission principal.
*
* @return String
* @param principalString
*/
private String getPrincipalKey(String principalString) {
return principalString.substring(principalString.indexOf(PRINCIPAL_SEPARATOR) + 1);
}
/**
* Returns the principal key portion of the IPermission principal.
*
* @return String
* @param perm org.apereo.portal.security.IPermission
* @exception AuthorizationException
*/
private String getPrincipalKey(IPermission perm) throws AuthorizationException {
return getPrincipalKey(perm.getPrincipal());
}
/**
* Returns the principal type portion of the principal.
*
* @return int
* @param principalString
*/
private int getPrincipalType(String principalString) {
return Integer.parseInt(
principalString.substring(0, principalString.indexOf(PRINCIPAL_SEPARATOR)));
}
/**
* Returns the principal type portion of the IPermission principal.
*
* @return int
* @param perm org.apereo.portal.security.IPermission
* @exception AuthorizationException
*/
private int getPrincipalType(IPermission perm) throws AuthorizationException {
return getPrincipalType(perm.getPrincipal());
}
/** @return java.lang.String */
private static String getSelectPermissionSql() {
if (selectPermissionSql == null) {
StringBuffer sqlBuff = new StringBuffer(200);
sqlBuff.append("SELECT ");
sqlBuff.append(getAllPermissionColumnsSql());
sqlBuff.append(" FROM ");
sqlBuff.append(PERMISSION_TABLE);
sqlBuff.append(" ");
selectPermissionSql = sqlBuff.toString();
}
return selectPermissionSql;
}
/** @return java.lang.String */
private static String getUpdatePermissionSql() {
if (updatePermissionSql == null) {
StringBuffer sqlBuff = new StringBuffer(300);
sqlBuff.append("UPDATE ");
sqlBuff.append(PERMISSION_TABLE);
sqlBuff.append(" SET ");
sqlBuff.append(TYPE_COLUMN);
sqlBuff.append(" = ?, ");
sqlBuff.append(EFFECTIVE_COLUMN);
sqlBuff.append(" = ?, ");
sqlBuff.append(EXPIRES_COLUMN);
sqlBuff.append(" = ? WHERE ");
sqlBuff.append(OWNER_COLUMN);
sqlBuff.append(" = ? AND ");
sqlBuff.append(PRINCIPAL_TYPE_COLUMN);
sqlBuff.append(" = ? AND ");
sqlBuff.append(PRINCIPAL_KEY_COLUMN);
sqlBuff.append(" = ? AND ");
sqlBuff.append(ACTIVITY_COLUMN);
sqlBuff.append(" = ? AND ");
sqlBuff.append(TARGET_COLUMN);
sqlBuff.append(" = ? ");
updatePermissionSql = sqlBuff.toString();
}
return updatePermissionSql;
}
/**
* @return org.apereo.portal.security.IPermission
* @param rs java.sql.ResultSet
*/
private IPermission instanceFromResultSet(ResultSet rs) throws SQLException {
Timestamp ts = null;
IPermission perm = newInstance(rs.getString(OWNER_COLUMN));
perm.setPrincipal(
rs.getString(PRINCIPAL_TYPE_COLUMN) + "." + rs.getString(PRINCIPAL_KEY_COLUMN));
perm.setActivity(rs.getString(ACTIVITY_COLUMN));
perm.setTarget(rs.getString(TARGET_COLUMN));
perm.setType(rs.getString(TYPE_COLUMN));
ts = rs.getTimestamp(EFFECTIVE_COLUMN);
if (ts != null) {
perm.setEffective(new Date(getTimestampMillis(ts)));
}
ts = rs.getTimestamp(EXPIRES_COLUMN);
if (ts != null) {
perm.setExpires(new Date(getTimestampMillis(ts)));
}
return perm;
}
/** Factory method for IPermissions */
public IPermission newInstance(String owner) {
return new PermissionImpl(owner);
}
/**
* Add the IPermissions to the store.
*
* @param perms org.apereo.portal.security.IPermission[]
* @exception Exception
*/
private void primAdd(IPermission[] perms) throws Exception {
Connection conn = null;
int rc = 0;
try {
conn = RDBMServices.getConnection();
String sQuery = getInsertPermissionSql();
PreparedStatement ps = conn.prepareStatement(sQuery);
try {
RDBMServices.setAutoCommit(conn, false);
for (int i = 0; i < perms.length; i++) {
primAdd(perms[i], ps);
if (log.isDebugEnabled()) log.debug("RDBMPermissionImpl.primAdd(): " + ps);
rc = ps.executeUpdate();
if (rc != 1) {
String errMsg = "Problem adding " + perms[i] + " RC: " + rc;
log.error(errMsg);
RDBMServices.rollback(conn);
throw new AuthorizationException(errMsg);
}
}
} finally {
ps.close();
}
RDBMServices.commit(conn);
} catch (Exception ex) {
log.error("Exception adding permissions " + perms, ex);
RDBMServices.rollback(conn);
throw ex;
} finally {
try {
RDBMServices.setAutoCommit(conn, true);
} finally {
RDBMServices.releaseConnection(conn);
}
}
}
/**
* Set the params on the PreparedStatement and execute the insert.
*
* @param perm org.apereo.portal.security.IPermission
* @param ps java.sql.PreparedStatement - the PreparedStatement for inserting a Permission row.
* @exception Exception
*/
private void primAdd(IPermission perm, PreparedStatement ps) throws Exception {
java.sql.Timestamp ts = null;
// NON-NULL COLUMNS:
ps.clearParameters();
ps.setString(1, perm.getOwner());
ps.setInt(2, getPrincipalType(perm));
ps.setString(3, getPrincipalKey(perm));
ps.setString(4, perm.getActivity());
ps.setString(5, perm.getTarget());
// TYPE:
if (perm.getType() == null) {
ps.setNull(6, Types.VARCHAR);
} else {
ps.setString(6, perm.getType());
}
// EFFECTIVE:
if (perm.getEffective() == null) {
ps.setNull(7, Types.TIMESTAMP);
} else {
ts = new java.sql.Timestamp(perm.getEffective().getTime());
ps.setTimestamp(7, ts);
}
// EXPIRES:
if (perm.getExpires() == null) {
ps.setNull(8, Types.TIMESTAMP);
} else {
ts = new java.sql.Timestamp(perm.getExpires().getTime());
ps.setTimestamp(8, ts);
}
}
/**
* Delete the IPermissions from the store.
*
* @param perms org.apereo.portal.security.IPermission[]
* @exception Exception
*/
private void primDelete(IPermission[] perms) throws Exception {
Connection conn = null;
try {
conn = RDBMServices.getConnection();
String sQuery = getDeletePermissionSql();
PreparedStatement ps = conn.prepareStatement(sQuery);
try {
RDBMServices.setAutoCommit(conn, false);
for (int i = 0; i < perms.length; i++) {
primDelete(perms[i], ps);
}
} finally {
ps.close();
}
RDBMServices.commit(conn);
} catch (Exception ex) {
log.error("Exception deleting permissions [" + perms + "]", ex);
RDBMServices.rollback(conn);
throw ex;
} finally {
try {
RDBMServices.setAutoCommit(conn, true);
} finally {
RDBMServices.releaseConnection(conn);
}
}
}
/**
* Set the params on the PreparedStatement and execute the delete.
*
* @param perm org.apereo.portal.security.IPermission
* @param ps java.sql.PreparedStatement - the PreparedStatement for deleting a Permission row.
* @return int - the return code from the PreparedStatement
* @exception Exception
*/
private int primDelete(IPermission perm, PreparedStatement ps) throws Exception {
ps.clearParameters();
ps.setString(1, perm.getOwner());
ps.setInt(2, getPrincipalType(perm));
ps.setString(3, getPrincipalKey(perm));
ps.setString(4, perm.getActivity());
ps.setString(5, perm.getTarget());
if (log.isDebugEnabled()) log.debug("RDBMPermissionImpl.primDelete(): " + ps);
return ps.executeUpdate();
}
/**
* Update the IPermissions in the store.
*
* @param perms org.apereo.portal.security.IPermission[]
* @exception Exception
*/
private void primUpdate(IPermission[] perms) throws Exception {
Connection conn = null;
try {
conn = RDBMServices.getConnection();
String sQuery = getUpdatePermissionSql();
PreparedStatement ps = conn.prepareStatement(sQuery);
try {
RDBMServices.setAutoCommit(conn, false);
for (int i = 0; i < perms.length; i++) {
primUpdate(perms[i], ps);
}
} finally {
ps.close();
}
RDBMServices.commit(conn);
} catch (Exception ex) {
log.error("Exception updating permissions " + perms, ex);
RDBMServices.rollback(conn);
throw ex;
} finally {
try {
RDBMServices.setAutoCommit(conn, true);
} finally {
RDBMServices.releaseConnection(conn);
}
}
}
/**
* Set the params on the PreparedStatement and execute the update.
*
* @param perm org.apereo.portal.security.IPermission
* @param ps java.sql.PreparedStatement - the PreparedStatement for updating a Permission row.
* @return int - the return code from the PreparedStatement
* @exception Exception
*/
private int primUpdate(IPermission perm, PreparedStatement ps) throws Exception {
java.sql.Timestamp ts = null;
// UPDATE COLUMNS:
ps.clearParameters();
// TYPE:
if (perm.getType() == null) {
ps.setNull(1, Types.VARCHAR);
} else {
ps.setString(1, perm.getType());
}
// EFFECTIVE:
if (perm.getEffective() == null) {
ps.setNull(2, Types.TIMESTAMP);
} else {
ts = new java.sql.Timestamp(perm.getEffective().getTime());
ps.setTimestamp(2, ts);
}
// EXPIRES:
if (perm.getExpires() == null) {
ps.setNull(3, Types.TIMESTAMP);
} else {
ts = new java.sql.Timestamp(perm.getExpires().getTime());
ps.setTimestamp(3, ts);
}
// WHERE COLUMNS:
ps.setString(4, perm.getOwner());
ps.setInt(5, getPrincipalType(perm));
ps.setString(6, getPrincipalKey(perm));
ps.setString(7, perm.getActivity());
ps.setString(8, perm.getTarget());
if (log.isDebugEnabled()) log.debug("RDBMPermissionImpl.primUpdate(): " + ps);
return ps.executeUpdate();
}
private void prepareSelectQuery(
PreparedStatement stmt,
String owner,
String principal,
String activity,
String target,
String type)
throws SQLException {
int i = 1;
if (owner != null) {
stmt.setString(i++, owner);
}
if (principal != null) {
stmt.setInt(i++, getPrincipalType(principal));
stmt.setString(i++, getPrincipalKey(principal));
}
if (activity != null) {
stmt.setString(i++, activity);
}
if (target != null) {
stmt.setString(i++, target);
}
if (type != null) {
stmt.setString(i++, type);
}
}
private String getSelectQuery(
String owner, String principal, String activity, String target, String type) {
StringBuffer sqlQuery = new StringBuffer(getSelectPermissionSql());
sqlQuery.append(" WHERE ");
if (owner != null) {
sqlQuery.append(OWNER_COLUMN);
sqlQuery.append(" = ? ");
} else {
sqlQuery.append("1 = 1 ");
}
if (principal != null) {
sqlQuery.append("AND ");
sqlQuery.append(PRINCIPAL_TYPE_COLUMN);
sqlQuery.append(" = ? AND ");
sqlQuery.append(PRINCIPAL_KEY_COLUMN);
sqlQuery.append(" = ? ");
}
if (activity != null) {
sqlQuery.append("AND ");
sqlQuery.append(ACTIVITY_COLUMN);
sqlQuery.append(" = ? ");
}
if (target != null) {
sqlQuery.append("AND ");
sqlQuery.append(TARGET_COLUMN);
sqlQuery.append(" = ? ");
}
if (type != null) {
sqlQuery.append("AND ");
sqlQuery.append(TYPE_COLUMN);
sqlQuery.append(" = ? ");
}
if (log.isTraceEnabled()) {
log.trace(
"Computed SQL query ["
+ sqlQuery
+ "] for owner=["
+ owner
+ "] and principal=["
+ principal
+ "] and activity=["
+ activity
+ "] and target=["
+ target
+ "] and type=["
+ type
+ "]");
}
return sqlQuery.toString();
}
/**
* Select the Permissions from the store.
*
* @param owner String - the Permission owner
* @param principal String - the Permission principal
* @param activity String - the Permission activity
* @exception AuthorizationException - wraps an Exception specific to the store.
*/
public IPermission[] select(
String owner, String principal, String activity, String target, String type)
throws AuthorizationException {
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
List<IPermission> perms = new ArrayList<IPermission>();
String query = getSelectQuery(owner, principal, activity, target, type);
try {
conn = RDBMServices.getConnection();
stmt = conn.prepareStatement(query);
prepareSelectQuery(stmt, owner, principal, activity, target, type);
try {
rs = stmt.executeQuery();
try {
while (rs.next()) {
perms.add(instanceFromResultSet(rs));
}
} finally {
rs.close();
}
} finally {
stmt.close();
}
} catch (SQLException sqle) {
log.error("Problem retrieving permissions", sqle);
throw new AuthorizationException(
"Problem retrieving Permissions ["
+ sqle.getMessage()
+ "] for query=["
+ query
+ "] for owner=["
+ owner
+ "] and principal=["
+ principal
+ "] and activity=["
+ activity
+ "] and target=["
+ target
+ "] and type=["
+ type
+ "]",
sqle);
} finally {
RDBMServices.releaseConnection(conn);
}
if (log.isTraceEnabled()) {
log.trace(
"RDBMPermissionImpl.select(): ["
+ query
+ "] for owner=["
+ owner
+ "] and principal=["
+ principal
+ "] and activity=["
+ activity
+ "] and target=["
+ target
+ "] and type=["
+ type
+ "] returned permissions ["
+ perms
+ "]");
}
return ((IPermission[]) perms.toArray(new IPermission[perms.size()]));
}
/**
* Update the IPermissions in the store.
*
* @param perms org.apereo.portal.security.IPermission[]
* @exception AuthorizationException - wraps an Exception specific to the store.
*/
public void update(IPermission[] perms) throws AuthorizationException {
if (perms.length > 0) {
try {
primUpdate(perms);
} catch (Exception ex) {
log.error("Exception updating permissions " + perms, ex);
throw new AuthorizationException(ex);
}
}
}
/**
* Update a single IPermission in the store.
*
* @param perm org.apereo.portal.security.IPermission
* @exception AuthorizationException - wraps an Exception specific to the store.
*/
public void update(IPermission perm) throws AuthorizationException {
Connection conn = null;
try {
conn = RDBMServices.getConnection();
String sQuery = getUpdatePermissionSql();
if (log.isDebugEnabled()) log.debug("RDBMPermissionImpl.update(): " + sQuery);
PreparedStatement ps = conn.prepareStatement(sQuery);
try {
primUpdate(perm, ps);
} finally {
ps.close();
}
} catch (Exception ex) {
log.error("Exception updating permission [" + perm + "]", ex);
throw new AuthorizationException("Problem updating Permission " + perm);
} finally {
RDBMServices.releaseConnection(conn);
}
}
/** @return long */
private static long getTimestampMillis(Timestamp ts) {
return ts.getTime();
}
}