package com.ibm.sbt.security.authentication.oauth.consumer.store; /* * © Copyright IBM Corp. 2012 * * 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. */ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.logging.Level; import java.util.logging.Logger; import javax.naming.Context; import javax.naming.InitialContext; import javax.sql.DataSource; import com.ibm.commons.util.StringUtil; import com.ibm.sbt.security.authentication.oauth.OAuthException; import com.ibm.sbt.security.authentication.oauth.consumer.AccessToken; import com.ibm.sbt.security.authentication.oauth.consumer.ConsumerToken; /** * @author mkataria * @date Dec 5, 2012 */ public class DBTokenStore implements TokenStore { // Consumer token .. application token // Access token .. user token static final String sourceClass = DBTokenStore.class.getName(); static final Logger logger = Logger.getLogger(sourceClass); private static boolean driverLoaded = false; private String jndiName; private String jdbcDriverClass; private String defaultJndiName = "jdbc/ibmsbt-dbtokenstore"; private TokenStoreEncryptor encryptorClass; final static String TYPE = "DBTOKENSTORE"; public DBTokenStore() { // setJdbcDriverClass("org.apache.derby.jdbc.EmbeddedDriver"); } @Override public ConsumerToken loadConsumerToken(String appId, String serviceName) throws OAuthException { return getAppToken(appId, serviceName); } @Override public void saveConsumerToken(String appId, String serviceName, ConsumerToken token) throws OAuthException { setAppToken(appId, serviceName, token); } @Override public AccessToken loadAccessToken(String appId, String serviceName, String consumerKey, String userId) throws OAuthException { return loadAccessToken(appId, serviceName, consumerKey, null, null, userId); } @Override public AccessToken loadAccessToken(String appId, String serviceName, String consumerKey, String moduleId, String tokenName, String userId) throws OAuthException { return getConsumerToken(appId, serviceName, userId); } @Override public void saveAccessToken(AccessToken token) throws OAuthException { setConsumerToken(token.getAppId(), token.getServiceName(), token.getConsumerKey(), token.getModuleId(), token.getTokenName(), token.getUserId(), token); } @Override public void deleteAccessToken(String appId, String serviceName, String consumerKey, String userId) throws OAuthException { deleteAccessToken(appId, serviceName, consumerKey, null, null, userId); } @Override public void deleteAccessToken(String appId, String serviceName, String consumerKey, String moduleId, String tokenName, String userId) throws OAuthException { deleteConsumerToken(appId, serviceName, userId); } /* * DAO Specific functions */ /* * Fetch the consumer token from DB */ private ConsumerToken getAppToken(String applicationId, String serviceName) throws OAuthException { Object token = null; try { Connection connection = getConnectionUsingJNDI(); try { PreparedStatement stmt = connection .prepareStatement("SELECT CONSUMERTOKEN FROM APPTOKEN WHERE APPID = ? AND SERVICENAME = ?"); try { stmt.setString(1, applicationId); stmt.setString(2, serviceName); ResultSet rs = stmt.executeQuery(); try { token = deSerializeObject(rs); byte[] fetchedToken = getEncryptorClass().decrypt(convertToBytes(token)); token = deSerializeObject(fetchedToken); } finally { rs.close(); } } finally { stmt.close(); } } finally { connection.close(); } return (ConsumerToken) token; } catch (SQLException e) { logger.log(Level.SEVERE, "getAppToken : ", e); throw new OAuthException(e, "DBTokenStore.java : getAppToken caused a SQLException"); } } /* * Insert app token */ private void setAppToken(String application, String serviceName, ConsumerToken token) throws OAuthException { try { Connection connection = getConnectionUsingJNDI(); try { PreparedStatement ps = connection.prepareStatement("INSERT INTO APPTOKEN VALUES (?, ?, ?)"); try { byte[] byteapptoken = convertToBytes(token); byteapptoken = getEncryptorClass().encrypt(byteapptoken); ps.setString(1, application); ps.setString(2, serviceName); ps.setObject(3, byteapptoken); ps.executeUpdate(); } finally { ps.close(); } } finally { connection.close(); } } catch (SQLException e) { logger.log(Level.SEVERE, "setAppToken : ", e); throw new OAuthException(e, "DBTokenStore.java : setAppToken caused a SQLException"); } } /* * Fetch user token */ private AccessToken getConsumerToken(String appId, String serviceName, String userId) throws OAuthException { Object token = null; try { Connection connection = getConnectionUsingJNDI(); try { //Issue 1478: Resolving issue with the Access Token // Changed SELECT ACCESSTOKEN FROM USERTOKEN WHERE APPID = ? AND SERVICENAME = ? AND USERID = ? to the proper query PreparedStatement stmt = connection .prepareStatement("SELECT SBTKREP.CREDENTIALTOKEN FROM SBTKREP WHERE APPID = ? AND SERVICENAME = ? AND USERID = ?"); try { stmt.setString(1, appId); stmt.setString(2, serviceName); stmt.setString(3, userId); ResultSet rs = stmt.executeQuery(); try { token = deSerializeObject(rs); System.err.println(" trying to print token information "+((AccessToken)token).getAppId()); byte[] fetchedToken = getEncryptorClass().decrypt(convertToBytes(token)); token = deSerializeObject(fetchedToken); } finally { rs.close(); } } finally { stmt.close(); } } finally { connection.close(); } return (AccessToken) token; } catch (SQLException e) { e.printStackTrace(); throw new OAuthException(e, "DBTokenStore.java : getConsumerToken caused a SQLException"); } } /* * Insert user token */ private void setConsumerToken(String appId, String serviceName, String consumerKey, String moduleId, String tokenName, String userId, Object token) throws OAuthException { try { Connection connection = getConnectionUsingJNDI(); try { //Issue 1478: Resolving issue with the Access Token // Change INSERT INTO USERTOKEN VALUES (?, ?, ?, ?) PreparedStatement ps = connection .prepareStatement("INSERT INTO SBTKREP (APPID,SERVICENAME,TYPE,USERID,CREDENTIALTOKEN) VALUES (?, ?, ?, ?, ?)"); try { ps.setString(1, appId); ps.setString(2, serviceName); ps.setString(3, TYPE); //added value for DBTokenStore ps.setString(4, userId); //Converts the AccessToken to a ByteStream and Encrypts it byte[] data = convertToBytes(token); data = getEncryptorClass().encrypt(data); ps.setObject(5, data); ps.executeUpdate(); } finally { ps.close(); } } finally { connection.close(); } } catch (SQLException e) { logger.log(Level.SEVERE, "setConsumerToken : ", e); throw new OAuthException(e, "DBTokenStore.java : setConsumerToken caused a SQLException"); } } /* * Delete user token */ private void deleteConsumerToken(String appId, String serviceName, String userId) throws OAuthException { try { Connection connection = getConnectionUsingJNDI(); try { PreparedStatement ps = connection .prepareStatement("DELETE FROM SBTKREP WHERE APPID = ? AND SERVICENAME = ? AND USERID = ?"); try { ps.setString(1, appId); ps.setString(2, serviceName); ps.setString(3, userId); ps.execute(); } finally { ps.close(); } } finally { connection.close(); } } catch (SQLException e) { logger.log(Level.SEVERE, "deleteConsumerToken : ", e); throw new OAuthException(e, "DBTokenStore.java : deleteConsumerToken caused a SQLException"); } } /* * Bean Properties */ public String getJndiName() { return jndiName; } public void setJndiName(String jndiName) { this.jndiName = jndiName; } public String getJdbcDriverClass() { return jdbcDriverClass; } public void setJdbcDriverClass(String jdbcDriverClass) { this.jdbcDriverClass = jdbcDriverClass; } public TokenStoreEncryptor getEncryptorClass() { return encryptorClass; } public void setEncryptorClass(TokenStoreEncryptor encryptorClass) { this.encryptorClass = encryptorClass; } // All utility methods here /* * Method for de-serializing the object from db to java object */ private Object deSerializeObject(ResultSet rs) throws OAuthException{ try { rs.next(); byte[] buf = rs.getBytes(1); if (buf != null) { Object deSerializedObject = deSerializeObject(buf); return deSerializedObject; } } catch (Exception e) { throw new OAuthException(e); } return null; } /* * Method for de-serializing the object from bytes to java object */ private Object deSerializeObject(byte[] tokendata) throws OAuthException{ try { ObjectInputStream objectIn = null; if (tokendata != null) { objectIn = new ObjectInputStream(new ByteArrayInputStream(tokendata)); Object deSerializedObject = objectIn.readObject(); return deSerializedObject; } } catch (Exception e) { throw new OAuthException(e); } return null; } /* * Read the database settings from JNDI */ private Connection getConnectionUsingJNDI() throws OAuthException { loadDBDriver(); try { Connection conn = null; String jndikey = getJndiName(); InitialContext initCtx = new InitialContext(); Context envCtx = (Context) initCtx.lookup("java:comp/env"); if(StringUtil.isEmpty(getJndiName())){ logger.log(Level.INFO, "DBTokenStore.java : getConnectionUsingJNDI : JNDI Key was blank in bean using the default"); jndikey = defaultJndiName; } DataSource ds = (DataSource) envCtx.lookup(jndikey); conn = ds.getConnection(); return conn; } catch (Exception e) { logger.log(Level.SEVERE, "DBTokenStore.java : getConnectionUsingJNDI : ", e); throw new OAuthException(e,"DBTokenStore.java : getConnectionUsingJNDI caused exeption" ); } } /* * Converts the input object to byte array for serializing into DB */ public byte[] convertToBytes(Object object) throws OAuthException { try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(object); oos.flush(); oos.close(); bos.close(); byte[] data = bos.toByteArray(); return data; } catch (Exception e) { throw new OAuthException(e,"DBTokenStore.java : getConnectionUsingJNDI caused exeption" ); } } /* * Load the DB Drivers */ private void loadDBDriver() throws OAuthException { if (driverLoaded) { return; } String driver = getJdbcDriverClass(); try { Class.forName(driver).newInstance(); // Load driver } catch (Exception ex) { logger.log(Level.SEVERE, "loadDBDriver : Could not load driver for class" + driver, ex); throw new OAuthException(ex,"DBTokenStore.java : loadDBDriver Could not load driver for class" + driver ); } driverLoaded = true; } }