/*
* (C) Copyright IBM Corp. 2012
*
* LICENSE: Eclipse Public License v1.0
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.ibm.gaiandb.security.server.authn;
/**
* An authenticator for the GaianDB token authentication strategy.
* Actors in the token authentication protocol are:
* 1. Client (initiates JDBC connection);
* 2. Derby database;
* 3. Token Manager (issues, authenticates and revokes token).
*
* The authentication protocol is:
* 1. Client establishes Security Token (ST) with Token Manager;
* 2. Client creates Connection (C1) with Derby (anonymously);
* 3. Client sends ST to Derby over C1 in a stored procedure call;
* 4. Derby generates a Session identity[1] (SID) and stores UID[2], ST and SID internally;
* 5. Derby returns SID to Client over C1;
* 6. Client terminates C1;
* 7. Client establishes Connection (C2) with Derby with UID and SID;
* 8. Derby verifies UID and SID (by comparing UID with user name in SID) and authenticates ST.
*
* [1] SID must be expressed in a String object.
* [2] Server extracts UID from ST.
*
* Security comment: This class (and any implementation) should not expose the tokens beyond the scope of this class (and its subclasses)
*/
import java.sql.SQLException;
import java.util.Hashtable;
import java.util.Properties;
import java.util.UUID;
import org.apache.derby.authentication.UserAuthenticator;
import org.apache.derby.impl.jdbc.authentication.BasicAuthenticationServiceImpl;
import com.ibm.gaiandb.Logger;
import com.ibm.gaiandb.security.common.SecurityToken;
public abstract class TokenUserAuthenticator implements UserAuthenticator {
// Use PROPRIETARY notice if class contains a main() method, otherwise use COPYRIGHT notice.
public static final String COPYRIGHT_NOTICE = "(c) Copyright IBM Corp. 2012";
private static final Logger logger = new Logger( "TokenUserAuthenticator", 30 );
static final String GAIAN_DEFAULTUID = "APP";
static final String GAIAN_SESSIONID = "SID";
static final String GAIAN_DID_KEY = "domain";
protected static TokenUserAuthenticator tua;
private Hashtable<String, String> sids = new Hashtable<String,String>(); // session id's and user names
/**
* authenticate the user using the credentials passed. If secure authentication fails, fallback to basic authentication.
* @param String userName
* @param String passwordOrSid
* @param String dbName
* @param Properties info
* @returns boolean whether the user was authenticated or not
*/
@Override
public boolean authenticateUser(String userName, String passwordOrSid, String dbName, Properties info) throws SQLException {
assert(userName != null);
boolean res = false;
// first call Derby DEFAULT authenticator
if (userName.equals(GAIAN_DEFAULTUID)) res = true; // handle initial client connection
else {
// handle "returning user" connection; expecting UID and SID
if (null != passwordOrSid) {
// expecting UID and SID
String pUID = userName;
String pSID = passwordOrSid;
String idRes = this.sids.get(pSID);
if (null != idRes && idRes.equals(pUID)) res = true;
}
BasicAuthenticationServiceImpl basAuth = new BasicAuthenticationServiceImpl();
if (!res) {
logger.logInfo("Couldn't authenticate securely, falling back to basic auth");
res = basAuth.authenticateUser(userName, passwordOrSid, dbName, new Properties()); // drop back to Basic if no asserted id
}
}
return res;
}
protected abstract boolean authenticateToken(SecurityToken token);
/**
* sets the token and returns the secure id from it.
* @param SecurityToken token
* @return String the secure id
*/
public static String setToken(SecurityToken token) {
String sid=null;
if (tua.authenticateToken(token)) {
String tid=token.getId();
if (null != tid) {
// generate unique SID
sid = UUID.randomUUID().toString(); // implementation uses Java's UUID
tua.sids.put(sid, tid); // add new SID to table
}
}
return sid;
}
}