/* See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* Esri Inc. 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
*
* 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 com.esri.gpt.framework.security.identity.local;
import com.esri.gpt.framework.context.RequestContext;
import com.esri.gpt.framework.security.identity.IdentityException;
import com.esri.gpt.framework.security.principal.User;
import com.esri.gpt.framework.sql.BaseDao;
import com.esri.gpt.framework.sql.ManagedConnection;
import com.esri.gpt.framework.util.UuidUtil;
import com.esri.gpt.framework.util.Val;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* Super-class for a database access objects associated with local
* identity tables.
*/
public class LocalDao extends BaseDao {
// class variables =============================================================
// instance variables ==========================================================
// constructors ================================================================
/** Default constructor. */
protected LocalDao() {
super();
}
/**
* Constructs with an associated request context.
* @param requestContext the request context
*/
public LocalDao(RequestContext requestContext) {
super(requestContext);
}
// properties ==================================================================
/**
* Gets the name of the user table.
* @return the table name
*/
protected String getUserTableName() {
return getRequestContext().getCatalogConfiguration().getUserTableName();
}
// methods =====================================================================
/**
* Determines if a username already exists.
* @param con the JDBC connection
* @param username the username to check
* @return true if a user by this name already exists
* @throws SQLException if a database exception occurs
*/
private boolean doesUsernameExist(Connection con, String username)
throws SQLException {
boolean bExists = false;
PreparedStatement st = null;
try {
StringBuffer sbSql = new StringBuffer();
sbSql.append("SELECT USERNAME FROM ").append(getUserTableName());
if (getIsDbCaseSensitive(this.getRequestContext())) {
sbSql.append(" WHERE UPPER(USERNAME)=?");
} else {
sbSql.append(" WHERE USERNAME=?");
}
logExpression(sbSql.toString());
st = con.prepareStatement(sbSql.toString());
st.setString(1,username.toUpperCase());
ResultSet rs = st.executeQuery();
if (rs.next()) {
bExists = true;
}
} finally {
closeStatement(st);
}
return bExists;
}
/**
* Ensures a local reference to a remote user.
* @param user the user (if user id less than zero, a record will be created)
* @throws IdentityException if an integrity violation occurs
* @throws SQLException if a database exception occurs
*/
public void ensureReferenceToRemoteUser(User user)
throws IdentityException, SQLException {
// establish the connection
ManagedConnection mc = returnConnection();
Connection con = mc.getJdbcConnection();
// if the local id has not been set,
// query for an existing reference,
// if none was found
// insert a new reference
int nUserId = user.getLocalID();
if (nUserId < 0) {
nUserId = readUserByDN(con,user);
if (nUserId < 0) {
String sDn = user.getDistinguishedName();
String sUsername = user.getName();
if ((sUsername.length() == 0) ||
(sUsername.length() > 64) ||
doesUsernameExist(con,sUsername)) {
String sMsg = "A valid userid was not auto-generated for remote user: "+sDn;
if (sUsername.length() == 0) {
sMsg += " The identity store username is empty.";
} else if (sUsername.length() > 64) {
sMsg += " The username is greater than 64 characters.";
} else {
sMsg += " This username already exists with a different DN.";
}
throw new IdentityException(sMsg);
}
insertUser(con,sDn,sUsername);
nUserId = readUserByDN(con,user);
if (nUserId < 0) {
String sMsg = "A valid userid was not auto-generated for remote user: "+sDn;
throw new IdentityException(sMsg);
}
}
}
}
/**
* Inserts a new user.
* @param con the JDBC connection
* @param dn the distinguished name
* @param username the username
* @param password the password
* @throws SQLException if a database exception occurs
*/
private void insertUser(Connection con, String dn, String username)
throws SQLException {
PreparedStatement st = null;
try {
String sSql = "INSERT INTO "+getUserTableName()+"(DN,USERNAME) VALUES(?,?)";
logExpression(sSql);
st = con.prepareStatement(sSql);
st.setString(1,dn);
st.setString(2,username);
st.execute();
} finally {
closeStatement(st);
}
}
/**
* Reads the distinguished name associated with a user id.
* @param userId the subject user id
* @return the associated distinguished name (empty if none)
* @throws SQLException if a database exception occurs
*/
public String readDN(int userId) throws SQLException {
return readValueByUserId("DN",userId);
}
/**
* Reads the local reference information for a user based upon
* the user's distinguished name.
* @param con the JDBC connection
* @param user user with distinguished name to check
* @return the local ID reference, -1 if none
* @throws IdentityException if an integrity violation occurs
* @throws SQLException if a database exception occurs
*/
private int readUserByDN(Connection con, User user)
throws IdentityException, SQLException {
int nUserId = -1;
String sUsername = "";
PreparedStatement st = null;
try {
// ensure that a distinguished name was supplied
if (user.getDistinguishedName().length() == 0) {
throw new IdentityException("Empty DN");
}
// query for the distinguished name reference within the local users table
String sSql = null;
if (getIsDbCaseSensitive(this.getRequestContext())) {
sSql = "SELECT USERID,USERNAME FROM "+getUserTableName()+" WHERE UPPER(DN)=?";
} else {
sSql = "SELECT USERID,USERNAME FROM "+getUserTableName()+" WHERE DN=?";
}
logExpression(sSql);
st = con.prepareStatement(sSql);
st.setString(1,user.getDistinguishedName().toUpperCase());
ResultSet rs = st.executeQuery();
int nCount = 0;
while (rs.next()) {
nUserId = rs.getInt(1);
sUsername = Val.chkStr(rs.getString(2));
// throw an exception if multiple users with the same
// distinguished name exist
nCount++;
if (nCount > 1) {
String sMsg = "Integrity violation within local user table: "+
"multiple references to same DN";
throw new IdentityException(sMsg);
}
}
} finally {
closeStatement(st);
}
if (nUserId >= 0) {
user.setLocalID(nUserId);
user.setName(sUsername);
}
return nUserId;
}
/**
* Reads the username associated with a user id.
* @param userId the subject user id
* @return the associated username (empty if none)
* @throws SQLException if a database exception occurs
*/
public String readUsername(int userId) throws SQLException {
return readValueByUserId("USERNAME",userId);
}
/**
* Reads a field value associated with a user id.
* @param field the field name
* @param userId the subject user id
* @return the associated value (empty if none)
* @throws SQLException if a database exception occurs
*/
private String readValueByUserId(String field, int userId)
throws SQLException {
String sValue = "";
ManagedConnection mc = returnConnection();
Connection con = mc.getJdbcConnection();
PreparedStatement st = null;
try {
String sSql = "SELECT "+field+" FROM "+getUserTableName()+" WHERE USERID=?";
logExpression(sSql);
st = con.prepareStatement(sSql);
st.setInt(1,userId);
ResultSet rs = st.executeQuery();
if (rs.next()) {
sValue = Val.chkStr(rs.getString(1));
}
} finally {
closeStatement(st);
}
return sValue;
}
}