/*
* Copyright (c) 2005-2008, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 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 org.wso2.carbon.identity.provider.openid.dao;
import org.apache.axiom.om.util.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openid4java.association.Association;
import org.wso2.carbon.identity.core.util.IdentityDatabaseUtil;
import org.wso2.carbon.identity.provider.openid.OpenIDServerConstants;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* The DAO used to access the identity database. This basically store, load and
* remove associations from the database.
*
* @author WSO2 Inc.
*/
public class OpenIDAssociationDAO {
private static final Log log = LogFactory.getLog(OpenIDAssociationDAO.class);
private String associationStore;
private static OpenIDAssociationDAO privateStore;
private static OpenIDAssociationDAO sharedStore;
static {
privateStore = new OpenIDAssociationDAO(OpenIDServerConstants.ASSOCIATION_STORE_TYPE_PRIVATE);
sharedStore = new OpenIDAssociationDAO(OpenIDServerConstants.ASSOCIATION_STORE_TYPE_SHARED);
}
/**
* Create the DAO with the identity database connection.
*
* @param dbConnection
* @param privateAssociations if this DAO stores private associations
*/
private OpenIDAssociationDAO(String storeType) {
associationStore = storeType;
}
public static OpenIDAssociationDAO getInstance(String storeType){
if(storeType.equals(OpenIDServerConstants.ASSOCIATION_STORE_TYPE_PRIVATE)){
return privateStore;
} else{
return sharedStore;
}
}
/**
* Tries to store the association in the identity database. But if the entry
* already exists this operation doesn't do anything useful.
*
* @param association
*/
public void storeAssociation(Association association) {
Connection connection = IdentityDatabaseUtil.getDBConnection();
PreparedStatement prepStmt = null;
try {
// if (!isAssociationExist(connection, association.getHandle())) {
prepStmt = connection.prepareStatement(OpenIDSQLQueries.STORE_ASSOCIATION);
prepStmt.setString(1, association.getHandle());
prepStmt.setString(2, association.getType());
prepStmt.setTimestamp(3, new java.sql.Timestamp(association.getExpiry().getTime()));
prepStmt.setString(4, Base64.encode(association.getMacKey().getEncoded()));
prepStmt.setString(5, associationStore);
prepStmt.execute();
connection.commit();
if(log.isDebugEnabled()) {
log.debug("Association " + association.getHandle() + " successfully stored in the database");
}
// } else {
// log.debug("Association " + association.getHandle() + " already exist in the database.");
// }
connection.commit();
} catch (SQLException e) {
log.error("Failed to store the association " + association.getHandle(), e);
} finally {
IdentityDatabaseUtil.closeStatement(prepStmt);
IdentityDatabaseUtil.closeConnection(connection);
}
}
/**
* Loads the association in the identity database.
*
* @param handle
* @return <code>Association</code>
*/
public Association loadAssociation(String handle) {
Connection connection = IdentityDatabaseUtil.getDBConnection();
PreparedStatement prepStmt = null;
ResultSet results = null;
try {
prepStmt = connection.prepareStatement(OpenIDSQLQueries.LOAD_ASSOCIATION);
prepStmt.setString(1, handle);
results = prepStmt.executeQuery();
if (results.next()) {
log.debug("Loading association " + handle);
return buildAssociationObject(results);
}
connection.commit();
} catch (SQLException e) {
log.error("Failed to load the association " + handle, e);
} finally {
IdentityDatabaseUtil.closeAllConnections(connection, results, prepStmt);
}
if(log.isDebugEnabled()) {
log.debug("Failed to load the association " + handle + " from the database");
}
return null;
}
/**
* Tries to remove the association from the database. But if the entry
* doesn't exist, then this method throws an exception.
*
* @param handle
*/
public void removeAssociation(String handle) {
Connection connection = IdentityDatabaseUtil.getDBConnection();
PreparedStatement prepStmt = null;
try {
if (isAssociationExist(connection, handle)) {
prepStmt = connection.prepareStatement(OpenIDSQLQueries.REMOVE_ASSOCIATION);
prepStmt.setString(1, handle);
prepStmt.execute();
connection.commit();
if(log.isDebugEnabled()) {
log.debug("Association " + handle + " successfully removed from the database");
}
} else {
if(log.isDebugEnabled()) {
log.debug("Association " + handle + " does not exist in the database");
}
}
} catch (SQLException e) {
log.error("Failed to remove the association " + handle, e);
} finally {
IdentityDatabaseUtil.closeStatement(prepStmt);
IdentityDatabaseUtil.closeConnection(connection);
}
}
/**
* Check if the entry exist in the database
*
* @param connection
* @return boolean
* @throws SQLException
*/
private boolean isAssociationExist(Connection connection, String handle) {
PreparedStatement prepStmt = null;
ResultSet results = null;
boolean result = false;
try {
prepStmt = connection.prepareStatement(OpenIDSQLQueries.CHECK_ASSOCIATION_ENTRY_EXIST);
prepStmt.setString(1, handle);
results = prepStmt.executeQuery();
if (results.next()) {
result = true;
log.debug("Association " + handle + " found");
}
} catch (SQLException e) {
log.error("Failed to load the association " + handle + ". Error while accessing the database. ", e);
} finally {
IdentityDatabaseUtil.closeResultSet(results);
IdentityDatabaseUtil.closeStatement(prepStmt);
}
log.debug("Association " + handle + " not found");
return result;
}
/**
* Builds the Association object
*
* @param results
* @return <code>Association</code>
* @throws SQLException
*/
private synchronized Association buildAssociationObject(ResultSet results) {
Association assoc = null;
String assocHandle = null;
try {
assocHandle = results.getString(1);
String assocType = results.getString(2);
java.util.Date expireIn = new java.util.Date(results.getTimestamp(3).getTime());
String macKey = results.getString(4);
String assocStore = results.getString(5);
// we check if params are missing
if (assocHandle == null || assocType == null || expireIn == null || macKey == null || assocStore == null) {
log.error("Required data missing. Cannot build the Association object");
return null;
}
// Here we check if we are loading the correct associations
if (associationStore.equals(OpenIDServerConstants.ASSOCIATION_STORE_TYPE_PRIVATE) &&
assocStore.equals(OpenIDServerConstants.ASSOCIATION_STORE_TYPE_SHARED)) {
log.error(
"Invalid association data found. Tried to load a Private Association but found a Shared Association");
return null;
} else if (associationStore.equals(OpenIDServerConstants.ASSOCIATION_STORE_TYPE_SHARED) &&
assocStore.equals(OpenIDServerConstants.ASSOCIATION_STORE_TYPE_PRIVATE)) {
log.error(
"Invalid association data found. Tried to load a Shared Association but found a Private Association");
return null;
}
// Checks for association handle
if (Association.TYPE_HMAC_SHA1.equals(assocType)) {
assoc = Association.createHmacSha1(assocHandle, Base64.decode(macKey), expireIn);
} else if (Association.TYPE_HMAC_SHA256.equals(assocType)) {
assoc = Association.createHmacSha256(assocHandle, Base64.decode(macKey), expireIn);
} else {
log.error("Invalid association type " + assocType + " loaded from database");
return null;
}
} catch (SQLException e) {
log.error("Failed to build the Association for " + assocHandle + ". Error while accessing the database.",
e);
} finally {
IdentityDatabaseUtil.closeResultSet(results);
}
log.debug("Association " + assocHandle + " loaded successfully from the database.");
return assoc;
}
}