not authenticating

This commit is contained in:
Derrick Johnson 2014-06-10 12:51:42 -05:00
parent 648bb38cd8
commit a83e51c9fa
29 changed files with 3023 additions and 2 deletions

34
pom.xml
View File

@ -119,11 +119,43 @@
<artifactId>jsr305</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<!-- <dependency>
<groupId>com.hp.csbu.cc</groupId>
<artifactId>CsMiddleware</artifactId>
<version>3.34.0</version>
</dependency> -->
<!-- removing CSMiddleware -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.3</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.9.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>
<!-- removing CSMiddleware -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>

View File

@ -0,0 +1,30 @@
package com.hp.csbu.cc.middleware;
import java.io.IOException;
import java.util.Map;
import org.apache.http.client.ClientProtocolException;
import org.apache.thrift.TException;
/*import org.apache.thrift.TException;
import com.hp.csbu.cc.security.cs.thrift.service.AuthResponse;
import com.hp.csbu.cc.security.cs.thrift.service.ResourceException;
import com.hp.csbu.cc.security.cs.thrift.service.SigAuthRequest; */
/**
* A client that can communicate to an authentication server for authentication.
*
* @author liemmn
*
*/
public interface AuthClient {
public Object validateTokenForServiceEndpointV2(String token,
String serviceIds, String endpointIds, boolean includeCatalog)
throws TException, ClientProtocolException; //ResourceException
public Object validateTokenForServiceEndpointV3(String token,
Map<String, String> inputParams) throws TException, ClientProtocolException; //ResourceException
//public AuthResponse validateSignature(SigAuthRequest request) throws ResourceException, TException;
}

View File

@ -0,0 +1,145 @@
package com.hp.csbu.cc.middleware;
import org.apache.commons.pool.impl.GenericObjectPool;
//import com.hp.csbu.cc.security.cs.thrift.service.CsThriftService.Client;
/**
* A factory for building {@link AuthClient}s.
*
* @author liemmn
*
*/
public abstract class AuthClientFactory {
private static AuthClientFactory instance = null;
protected static GenericObjectPool pool;
/**
* Build a AuthClientFactory. Singleton.
*
* @param host
* Auth host
* @param port
* Auth port
* @param timeout
* Auth connection timeout
* @param clientAuth
* 2-way SSL (if false, 1-way SSL is used)
* @param keyStore
* Keystore
* @param keyPass
* Keystore password
* @param trustStore
* Truststore
* @param trustPass
* Truststore password
* @param maxActive
* Maximum number of objects that can be allocated by the pool
* (checked out to clients, or idle awaiting checkout) at a given
* time. When non-positive, there is no limit to the number of
* objects that can be managed by the pool at one time. When
* maxActive is reached, the pool is said to be exhausted. The
* default setting for this parameter is 8.
* @param maxIdle
* Maximum number of objects that can sit idle in the pool at any
* time. When negative, there is no limit to the number of
* objects that may be idle at one time. The default setting for
* this parameter is 8.
* @param timeBetweenEvictionRunsMillis
* How long the eviction thread should sleep before "runs" of
* examining idle objects. When non-positive, no eviction thread
* will be launched. The default setting for this parameter is -1
* (i.e., idle object eviction is disabled by default).
* @param minEvictableIdleTimeMillis
* Minimum amount of time that an object may sit idle in the pool
* before it is eligible for eviction due to idle time. When
* non-positive, no object will be dropped from the pool due to
* idle time alone. This setting has no effect unless
* timeBetweenEvictionRunsMillis > 0. The default setting for
* this parameter is 30 minutes.
* @param adminToken
* Admin token for use with vanilla Keystone.
*
* @return AuthClientFactory singleton.
* @throws Exception
*/
public static synchronized AuthClientFactory build(String host, int port,
int timeout, boolean clientAuth, String keyStore, String keyPass,
String trustStore, String trustPass, int maxActive, int maxIdle,
long timeBetweenEvictionRunsMillis,
long minEvictableIdleTimeMillis, String adminToken)
throws Exception {
if (instance == null) {
/*if (port == 9543) {
instance = new ThriftClientFactory(host, port, timeout,
clientAuth, keyStore, keyPass, trustStore, trustPass);
} else {*/
instance = new HttpClientFactory(host, port, timeout,
clientAuth, keyStore, keyPass, trustStore, trustPass,
adminToken, maxActive, timeBetweenEvictionRunsMillis,
minEvictableIdleTimeMillis);
// }
// Pool tweaking
pool.setMaxActive(maxActive);
pool.setMaxIdle(maxIdle);
pool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
pool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
}
return instance;
}
/**
* Get a client. Don't forget to {@link #recycleClient(Client)} after you
* are done using it, successfully or not.
*
* @return Client
* @throws Exception
*/
public AuthClient getClient() {
try {
return (AuthClient) pool.borrowObject();
} catch (Exception e) {
throw new AuthConnectionException("Failed to get a client "+ e.getMessage(), e);
}
}
/**
* Recycle the client for next usage.
*
* @param client
* Client to recycle
* @throws Exception
*/
public void recycle(AuthClient client) {
try {
pool.returnObject(client);
} catch (Exception e) {
throw new AuthConnectionException("Failed to recycle client", e);
}
}
/**
* Call this if the client is unusable (i.e., exception).
*
* @param client
* Client to discard.
*/
public void discard(AuthClient client) {
try {
pool.invalidateObject(client);
} catch (Exception e) {
throw new AuthConnectionException("Failed to destroy client", e);
}
}
/**
* Shut down this factory.
*/
public void shutdown() {
try {
pool.close();
} catch (Exception e) {
throw new AuthConnectionException("Failed to close client pool", e);
}
}
}

View File

@ -0,0 +1,18 @@
package com.hp.csbu.cc.middleware;
/**
* An exception to indicate any connection issue.
*
* @author liemmn
*
*/
public class AuthConnectionException extends RuntimeException {
private static final long serialVersionUID = 4318025130590973448L;
public AuthConnectionException(String msg) {
super(msg);
}
public AuthConnectionException(String msg, Exception e) {
super(msg, e);
}
}

View File

@ -0,0 +1,183 @@
package com.hp.csbu.cc.middleware;
public interface AuthConstants {
/** 'Confirmed' or 'Invalid' */
public static enum IdentityStatus {
Confirmed, Invalid
}
// =============================== TOKEN ===================================
/** Credential (token) header */
public static final String TOKEN = "X-AUTH-TOKEN";
/** Auth status parameter */
public static final String AUTH_IDENTITY_STATUS = "X-IDENTITY-STATUS";
/** Auth user Id parameter */
public static final String AUTH_USER_ID = "X-USER-ID";
/** Auth user name parameter */
public static final String AUTH_USER_NAME = "X-USER-NAME";
/** Auth user roles parameter, comma-separated roles */
public static final String AUTH_ROLES = "X-ROLES";
/** json encoded keystone service catalog */
public static final String AUTH_SERVICE_CATALOG = "X-SERVICE-CATALOG";
/** Service Ids initialization parameter */
public static final String SERVICE_IDS = "ServiceIds";
/** Endpoint Ids initialization parameter */
public static final String ENDPOINT_IDS = "EndpointIds";
/** Keystone admin token for use in vanilla Keystone */
public static final String ADMIN_TOKEN = "AdminToken";
// ============================ CONNECTION =================================
/** Auth server initialization parameter */
public static final String SERVER_VIP = "ServerVIP";
/** Auth server port: 9543 for Thrift, 35357 for HTTP. */
public static final String SERVER_PORT = "ServerPort";
/** connection timeout initialization parameter */
public static final String CONN_TIMEOUT = "ConnTimeout";
/** 2-way SSL initialization parameter: True or False */
public static final String CONN_SSL_CLIENT_AUTH = "ConnSSLClientAuth";
/** SSL keystore initialization parameter */
public static final String KEYSTORE = "Keystore";
/** SSL keystore password initialization parameter */
public static final String KEYSTORE_PASS = "KeystorePass";
/** SSL truststore initialization parameter */
public static final String TRUSTSTORE = "Truststore";
/** SSL truststore password initialization parameter */
public static final String TRUSTSTORE_PASS = "TruststorePass";
// ============================== POOLING ==================================
/**
* Maximum number of objects that can be allocated by the pool (checked out
* to clients, or idle awaiting checkout) at a given time. When
* non-positive, there is no limit to the number of objects that can be
* managed by the pool at one time. When maxActive is reached, the pool is
* said to be exhausted. The default setting for this parameter is 8.
*/
public static final String CONN_POOL_MAX_ACTIVE = "ConnPoolMaxActive";
/**
* Maximum number of objects that can sit idle in the pool at any time. When
* negative, there is no limit to the number of objects that may be idle at
* one time. The default setting for this parameter is 8.
*/
public static final String CONN_POOL_MAX_IDLE = "ConnPoolMaxIdle";
/**
* How long the eviction thread should sleep before "runs" of examining idle
* objects. When non-positive, no eviction thread will be launched. The
* default setting for this parameter is -1 (i.e., idle object eviction is
* disabled by default).
*/
public static final String CONN_POOL_EVICT_PERIOD = "ConnPoolEvictPeriod";
/**
* Minimum amount of time that an object may sit idle in the pool before it
* is eligible for eviction due to idle time. When non-positive, no object
* will be dropped from the pool due to idle time alone. This setting has no
* effect unless ConnPoolEvictPeriod > 0. The default setting for this
* parameter is 30 minutes.
*/
public static final String CONN_POOL_MIN_IDLE_TIME = "ConnPoolMinIdleTime";
// ============================== CACHING ==================================
/** Memcache hosts */
public static final String MEMCACHE_HOSTS = "MemcacheHosts";
/** Memcache connection timeout */
public static final String MEMCACHE_TIMEOUT = "MemcacheTimeout";
/** Memcache encryption */
public static final String MEMCACHE_ENCRYPT = "MemcacheEncrypt";
/** Number of connection timeout retries **/
public static final String CONN_TIMEOUT_RETRIES = "ConnRetryTimes";
/** Number of connection timeout retries **/
public static final String PAUSE_BETWEEN_RETRIES = "ConnRetryInterval";
/** Authentication decision is forwarded to next filter **/
public static final String DELAY_AUTH_DECISION = "DelayAuthDecision";
public static final String SIGNATURE_METHOD = "HmacSHA1";
/** Version of CS to authenticate the credentials **/
public static final String AUTH_VERSION = "AuthVersion";
/** Include Service Catalog as part of Authentication Response **/
public static final String INCLUDE_SERVICE_CATALOG = "IncludeServiceCatalog";
/**
* Identity service managed unique identifier, string. Only present if this
* is a project-scoped v3 token, or a tenant-scoped v2 token.
**/
public static final String AUTH_PROJECT_ID = "X-PROJECT-ID";
/**
* Project name, unique within owning domain, string. Only present if this
* is a project-scoped v3 token, or a tenant-scoped v2 token.
**/
public static final String AUTH_PROJECT_NAME = "X-PROJECT-NAME";
/**
* Identity service managed unique identifier of owning domain of project,
* string. Only present if this is a project-scoped v3 token. If this
* variable is set, this indicates that the PROJECT_NAME can only be assumed
* to be unique within this domain.
**/
public static final String AUTH_PROJECT_DOMAIN_ID = "X-PROJECT-DOMAIN-ID";
/**
* Name of owning domain of project, string. Only present if this is a
* project-scoped v3 token. If this variable is set, this indicates that the
* PROJECT_NAME can only be assumed to be unique within this domain.
**/
public static final String AUTH_PROJECT_DOMAIN_NAME = "X-PROJECT-DOMAIN-NAME";
/**
* Identity service managed unique identifier of owning domain of user,
* string. If this variable is set, this indicates that the USER_NAME can
* only be assumed to be unique within this domain.
**/
public static final String AUTH_USER_DOMAIN_ID = "X-USER-DOMAIN-ID";
/**
* Name of owning domain of user, string. If this variable is set, this
* indicates that the USER_NAME can only be assumed to be unique within this
* domain.
**/
public static final String AUTH_USER_DOMAIN_NAME = "X-USER-DOMAIN-NAME";
/**
* Identity service managed unique identifier, string. Only present if this
* is a domain-scoped v3 token.
**/
public static final String AUTH_DOMAIN_ID = "X-DOMAIN-ID";
/**
* Unique domain name, string. Only present if this is a domain-scoped v3
* token.
**/
public static final String AUTH_DOMAIN_NAME = "X-DOMAIN-NAME";
public static final String AUTH_HP_IDM_ROLES = "X-HP-IDM-Non-Tenant-Roles";
public static final String REMOTE_HOST = "RemoteHost";
public static final String REMOTE_ADDR = "RemoteAddress";
// Depracated Headers.
/** Auth user roles parameter, comma-separated roles */
public static final String AUTH_ROLE = "X-ROLE";
/** Auth tenant Id parameter */
public static final String AUTH_TENANT_ID = "X-TENANT-ID";
/** Auth tenant name parameter */
public static final String AUTH_TENANT_NAME = "X-TENANT-NAME";
/** Auth tenant name parameter */
public static final String AUTH_TENANT = "X-TENANT";
/**
* *Deprecated* in favor of HTTP_X_USER_ID and HTTP_X_USER_NAME User name,
* unique within owning domain, string
**/
public static final String AUTH_USER = "X-USER";
public static final String AUTH_SUBJECT_TOKEN = "X-Subject-Token";
public static final String ADMIN_USER = "AdminUser";
public static final String ADMIN_PASSWORD = "AdminPassword";
public static final String ADMIN_AUTH_METHOD = "AdminAuthMethod";
public static final String ADMIN_ACCESS_KEY = "AdminAccessKey";
public static final String ADMIN_SECRET_KEY = "AdminSecretKey";
public static final String ADMIN_PROJECT_ID = "AdminProjectId";
}

View File

@ -0,0 +1,19 @@
package com.hp.csbu.cc.middleware;
/**
* An exception to indicate any authentication error.
*
* @author liemmn
*
*/
public class AuthException extends RuntimeException {
private static final long serialVersionUID = 2287073516214658461L;
public AuthException(String msg) {
super(msg);
}
public AuthException(String msg, Exception e) {
super(msg, e);
}
}

View File

@ -0,0 +1,31 @@
package com.hp.csbu.cc.middleware;
import java.util.List;
public class CatalogV3 {
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List getEndPoints() {
return endPoints;
}
public void setEndPoints(List endPoints) {
this.endPoints = endPoints;
}
String id;
String type;
List endPoints;
}

View File

@ -0,0 +1,294 @@
package com.hp.csbu.cc.middleware;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Config implements AuthConstants {
// Thee faithful logger
private static final Logger logger = LoggerFactory
.getLogger(Config.class);
private static final Config instance = new Config();
private static final String PASSWORD = "password";
private static final String ACCESS_KEY = "accesskey";
// Application wide init param -- ServletContext
private ServletContext context = null;
// Memcache client--There shall only be one
///private MemcacheCrypt client = null;
private TokenCache<String, String> client = null;
// Auth client factory
private AuthClientFactory factory = null;
// The service IDs that this filter serves
private String serviceIds;
// The optional endpoint IDs that this filter serves
private String endpointIds;
// Memcache timeout value
private long memCacheTimeOut;
// flag to set if auth decision can be delegated to next filter
private boolean delayAuthDecision;
// retries and pauseTime configuration for retry logic
private int retries;
private int pauseTime;
// configuration to authenticate against CS api
private String authVersion;
// flag to include catalog in the response
private boolean includeCatalog;
// configuration for admin authentication method to be used for 2-way SSL
private String adminAuthMethod;
// configuration for admin default project
private String adminProjectId;
// flag to indicate if the filter is already intialized with required parameters
private volatile boolean initialized = false;
//context is not getting properly filed so will use FilterConfig
private FilterConfig filterConfig;
private Config() {
}
public static Config getInstance() {
return instance;
}
public synchronized void initialize(FilterConfig config) throws ServletException {
this.context = config.getServletContext();
this.filterConfig = config;
try {
// Initialize serviceIds...
//serviceIds = context.getInitParameter(SERVICE_IDS);
serviceIds = filterConfig.getInitParameter(SERVICE_IDS);
// Initialize endpointIds...
//endpointIds = context.getInitParameter(ENDPOINT_IDS);
endpointIds = filterConfig.getInitParameter(ENDPOINT_IDS);
String somthing = context
.getInitParameter(SERVER_PORT);
// Initialize auth server connection parameters...
//String host = context.getInitParameter(SERVER_VIP);
String host = filterConfig.getInitParameter(SERVER_VIP);
//int port = Integer.parseInt(context
// .getInitParameter(SERVER_PORT));
int port = Integer.parseInt(filterConfig.getInitParameter(SERVER_PORT));
// HP Keystone Server only supports authentication against
// V3.0 api
authVersion = getValue(AUTH_VERSION, "v3.0");
if ((serviceIds == null || serviceIds.isEmpty())
&& (endpointIds == null || endpointIds.isEmpty())
&& authVersion.equalsIgnoreCase("v2.0")) {
throw new Throwable("Need to specify " + SERVICE_IDS);
}
// Initialize memcache...
String cacheHosts = context.getInitParameter(MEMCACHE_HOSTS);
boolean isEncrypted = Boolean.valueOf(context
.getInitParameter(MEMCACHE_ENCRYPT));
memCacheTimeOut = getValue(MEMCACHE_TIMEOUT, 2000L);
/* if (cacheHosts != null && !cacheHosts.isEmpty()) {
this.client = new MemcacheCrypt(cacheHosts, isEncrypted);
}*/
this.client = new TokenCache<>(getValue(MEMCACHE_TIMEOUT,2000L));
// Initialize Certificates
/*String keyStore = context.getInitParameter(KEYSTORE);
String keyPass = context.getInitParameter(KEYSTORE_PASS);
String trustStore = context.getInitParameter(TRUSTSTORE);
String trustPass = context.getInitParameter(TRUSTSTORE_PASS);*/
String keyStore = filterConfig.getInitParameter(KEYSTORE);
String keyPass = filterConfig.getInitParameter(KEYSTORE_PASS);
String trustStore = filterConfig.getInitParameter(TRUSTSTORE);
String trustPass = filterConfig.getInitParameter(TRUSTSTORE_PASS);
String adminToken = getValue(ADMIN_TOKEN, "");
int timeout = getValue(CONN_TIMEOUT, 0);
boolean clientAuth = getValue(CONN_SSL_CLIENT_AUTH, true);
int maxActive = getValue(CONN_POOL_MAX_ACTIVE, 3);
int maxIdle = getValue(CONN_POOL_MAX_IDLE, 3);
long evictPeriod = getValue(CONN_POOL_EVICT_PERIOD, 60000L);
long minIdleTime = getValue(CONN_POOL_MIN_IDLE_TIME, 90000L);
retries = getValue(CONN_TIMEOUT_RETRIES, 3);
pauseTime = getValue(PAUSE_BETWEEN_RETRIES, 100);
delayAuthDecision = getValue(DELAY_AUTH_DECISION, false);
includeCatalog = getValue(INCLUDE_SERVICE_CATALOG, true);
adminAuthMethod = getValue(ADMIN_AUTH_METHOD, "");
adminProjectId = getValue(ADMIN_PROJECT_ID, "");
this.factory = AuthClientFactory.build(host, port, timeout,
clientAuth, keyStore, keyPass, trustStore, trustPass,
maxActive, maxIdle, evictPeriod, minIdleTime, adminToken);
verifyRequiredParamsForAuthMethod();
logger.info("Auth host (2-way SSL: " + clientAuth + "): " + host);
logger.info("Read Servlet Initialization Parameters ");
initialized = true;
} catch (Throwable t) {
logger.error("Failed to read Servlet Initialization Parameters ",
t.getMessage());
throw new ServletException(
"Failed to read Servlet Initialization Parameters :: "
+ t.getMessage(), t);
}
}
public boolean isInitialized() {
return initialized;
}
protected String getAdminProject() {
return adminProjectId;
}
protected String getAdminAccessKey() {
if (context.getAttribute(ADMIN_ACCESS_KEY) != null) {
return (String) context.getAttribute(ADMIN_ACCESS_KEY);
} else {
return getValue(ADMIN_ACCESS_KEY, "");
}
}
protected String getAdminSecretKey() {
if (context.getAttribute(ADMIN_SECRET_KEY) != null) {
return (String) context.getAttribute(ADMIN_SECRET_KEY);
} else {
return getValue(ADMIN_SECRET_KEY, "");
}
}
protected String getAdminAuthMethod() {
return adminAuthMethod;
}
protected String getAdminUser() {
if (context.getAttribute(ADMIN_USER) != null) {
return (String) context.getAttribute(ADMIN_USER);
} else {
return getValue(ADMIN_USER, "");
}
}
protected String getAdminPassword() {
if (context.getAttribute(ADMIN_PASSWORD) != null) {
return (String) context.getAttribute(ADMIN_PASSWORD);
} else {
return getValue(ADMIN_PASSWORD, "");
}
}
protected boolean isIncludeCatalog() {
return includeCatalog;
}
protected long getMemCacheTimeOut() {
return memCacheTimeOut;
}
protected String getAuthVersion() {
return authVersion;
}
protected void setMemCacheTimeOut(long memCacheTimeOut) {
this.memCacheTimeOut = memCacheTimeOut;
}
// Is caching enabled?
protected boolean isCaching() {
//return this.client != null;
return false;
}
protected ServletContext getConfig() {
return context;
}
/*protected MemcacheCrypt getClient() {
return client;
}*/
protected TokenCache getClient() {
return client;
}
protected AuthClientFactory getFactory() {
return factory;
}
protected String getServiceIds() {
return serviceIds;
}
protected String getEndpointIds() {
return endpointIds;
}
protected boolean isDelayAuthDecision() {
return delayAuthDecision;
}
protected int getRetries() {
return retries;
}
protected int getPauseTime() {
return pauseTime;
}
private <T> T getValue(String paramName, T defaultValue) {
Class type = defaultValue.getClass();
//String initparamValue = context.getInitParameter(paramName);
String initparamValue = filterConfig.getInitParameter(paramName);
if (initparamValue != null && !initparamValue.isEmpty()) {
if (type.equals(Integer.class)) {
int paramValue = Integer.parseInt(initparamValue);
return (T) type.cast(paramValue);
} else if (type.equals(Long.class)) {
long paramValue = Long.parseLong(initparamValue);
return (T) type.cast(paramValue);
} else if (type.equals(Boolean.class)) {
boolean paramValue = Boolean.parseBoolean(initparamValue);
return (T) type.cast(paramValue);
} else if (type.equals(String.class)) {
return (T) type.cast(initparamValue);
}
}
return defaultValue;
}
private void verifyRequiredParamsForAuthMethod() {
if (adminAuthMethod.equalsIgnoreCase(PASSWORD)) {
if (getAdminUser().isEmpty() || getAdminPassword().isEmpty()) {
String msg = String
.format("admin user and password must be specified if admin auth method is %s",
adminAuthMethod);
throw new AuthException(msg);
}
} else if (adminAuthMethod.equalsIgnoreCase(ACCESS_KEY)) {
if (getAdminAccessKey().isEmpty() || getAdminSecretKey().isEmpty()) {
String msg = String
.format("admin access and secret key must be specified if admin auth method is %s",
adminAuthMethod);
throw new AuthException(msg);
}
}
}
}

View File

@ -0,0 +1,19 @@
package com.hp.csbu.cc.middleware;
/**
* An exception caused for memcache decryption issues.
*
* @author liemmn
*
*/
public class DecryptionException extends RuntimeException {
private static final long serialVersionUID = 5463487714560524511L;
public DecryptionException(String msg) {
super(msg);
}
public DecryptionException(String msg, Exception e) {
super(msg, e);
}
}

View File

@ -0,0 +1,19 @@
package com.hp.csbu.cc.middleware;
/**
* Memcache encryption exception.
*
* @author liemmn
*
*/
public class EncryptionException extends RuntimeException {
private static final long serialVersionUID = 8249423387842730866L;
public EncryptionException(String msg) {
super(msg);
}
public EncryptionException(String msg, Exception e) {
super(msg, e);
}
}

View File

@ -0,0 +1,42 @@
package com.hp.csbu.cc.middleware;
public class ExceptionHandlerUtil {
public final static String SERVICE_UNAVAILABLE = "Service Unavailable";
public final static String UNAUTHORIZED_TOKEN = "Unauthorized Token";
public final static String INTERNAL_SERVER_ERROR = "Internal Server Error";
private ExceptionHandlerUtil() {
}
public static String getStatusText(int errorCode) {
if (errorCode == 401) {
return UNAUTHORIZED_TOKEN;
}
if (errorCode == 503) {
return SERVICE_UNAVAILABLE;
}
if (errorCode == 500) {
return INTERNAL_SERVER_ERROR;
}
return "Unknown Error";
}
public static TokenExceptionHandler lookUpTokenException(Exception ex) {
try {
return TokenExceptionHandler.valueOf(ex.getClass().getSimpleName());
} catch (IllegalArgumentException iae) {
return TokenExceptionHandler.valueOf("ResourceException");
}
}
/*public static SignatureExceptionHandler lookUpSignatureException(Exception ex) {
try {
return SignatureExceptionHandler.valueOf(ex.getClass().getSimpleName());
} catch (IllegalArgumentException iae) {
return SignatureExceptionHandler.valueOf("ResourceException");
}
} */
}

View File

@ -0,0 +1,471 @@
package com.hp.csbu.cc.middleware;
import static com.hp.csbu.cc.middleware.AuthConstants.AUTH_DOMAIN_ID;
import static com.hp.csbu.cc.middleware.AuthConstants.AUTH_DOMAIN_NAME;
import static com.hp.csbu.cc.middleware.AuthConstants.AUTH_HP_IDM_ROLES;
import static com.hp.csbu.cc.middleware.AuthConstants.AUTH_IDENTITY_STATUS;
import static com.hp.csbu.cc.middleware.AuthConstants.AUTH_PROJECT_DOMAIN_ID;
import static com.hp.csbu.cc.middleware.AuthConstants.AUTH_PROJECT_DOMAIN_NAME;
import static com.hp.csbu.cc.middleware.AuthConstants.AUTH_PROJECT_ID;
import static com.hp.csbu.cc.middleware.AuthConstants.AUTH_PROJECT_NAME;
import static com.hp.csbu.cc.middleware.AuthConstants.AUTH_ROLE;
import static com.hp.csbu.cc.middleware.AuthConstants.AUTH_ROLES;
import static com.hp.csbu.cc.middleware.AuthConstants.AUTH_SERVICE_CATALOG;
import static com.hp.csbu.cc.middleware.AuthConstants.AUTH_TENANT;
import static com.hp.csbu.cc.middleware.AuthConstants.AUTH_TENANT_NAME;
import static com.hp.csbu.cc.middleware.AuthConstants.AUTH_USER;
import static com.hp.csbu.cc.middleware.AuthConstants.AUTH_USER_DOMAIN_ID;
import static com.hp.csbu.cc.middleware.AuthConstants.AUTH_USER_DOMAIN_NAME;
import static com.hp.csbu.cc.middleware.AuthConstants.AUTH_USER_ID;
import static com.hp.csbu.cc.middleware.AuthConstants.AUTH_TENANT_ID;
import static com.hp.csbu.cc.middleware.AuthConstants.AUTH_USER_NAME;
import static com.hp.csbu.cc.middleware.AuthConstants.IdentityStatus;
/*import com.hp.csbu.cc.security.cs.thrift.service.AuthResponseV2;
import com.hp.csbu.cc.security.cs.thrift.service.AuthResponseV3;
import com.hp.csbu.cc.security.cs.thrift.service.EndpointV3;
import com.hp.csbu.cc.security.cs.thrift.service.Role;
import com.hp.csbu.cc.security.cs.thrift.service.ServiceForCatalogV3;
import com.hp.csbu.cc.security.cs.thrift.service.V3Role;
*/
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeoutException;
import javax.servlet.ServletRequest;
//import net.rubyeye.xmemcached.exception.MemcachedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
public class FilterUtils {
private FilterUtils() {
}
private static final Config appConfig = Config.getInstance();
private static final Gson gson = new GsonBuilder()
.excludeFieldsWithModifiers(Modifier.PRIVATE, Modifier.FINAL)
.create();
// Thee faithful logger
private static final Logger logger = LoggerFactory
.getLogger(FilterUtils.class);
public static void destroyFilter() {
/*MemcacheCrypt client = appConfig.getClient();
// Shutdown memcache
if (client != null) {
try {
client.shutdown();
} catch (IOException e) {
logger.warn("Failed to shutdown memcache", e);
}
} */
AuthClientFactory factory = appConfig.getFactory();
// Shutdown factory
if (factory != null) {
factory.shutdown();
}
}
public static ServletRequest wrapRequestFromHttpResponse(
ServletRequest req, String data) {
if (appConfig.getAuthVersion().equalsIgnoreCase("v2.0")) {
wrapRequestFromHttpV2Response(req, data);
} else {
wrapRequestFromHttpV3Response(req, data);
}
return req;
}
private static void wrapRequestFromHttpV3Response(ServletRequest req,
String data) {
StringBuilder tenants = new StringBuilder();
StringBuilder nonTenants = new StringBuilder();
JsonParser jp = new JsonParser();
JsonObject token = jp.parse(data).getAsJsonObject().get("token")
.getAsJsonObject();
// Domain Scoped Token
if (token.get("domain") != null) {
JsonObject domain = token.get("domain").getAsJsonObject();
req.setAttribute(AUTH_DOMAIN_ID, domain.get("id").getAsString());
if (domain.get("name") != null) {
req.setAttribute(AUTH_DOMAIN_NAME, domain.get("name")
.getAsString());
}
}
// Project Scoped Token
if (token.get("project") != null) {
JsonObject project = token.get("project").getAsJsonObject();
req.setAttribute(AUTH_PROJECT_ID, project.get("id").getAsString());
req.setAttribute(AUTH_PROJECT_NAME, project.get("name")
.getAsString());
JsonObject projectDomain = project.get("domain").getAsJsonObject();
// special case where the value of id is null and the
// projectDomain.get("id") != null
if (!projectDomain.get("id").equals(new JsonNull())) {
req.setAttribute(AUTH_PROJECT_DOMAIN_ID, projectDomain
.get("id").getAsString());
}
if (projectDomain.get("name") != null) {
req.setAttribute(AUTH_PROJECT_DOMAIN_NAME,
projectDomain.get("name"));
}
}
// User info
if (token.get("user") != null) {
JsonObject user = token.get("user").getAsJsonObject();
req.setAttribute(AUTH_USER_ID, user.get("id").getAsString());
req.setAttribute(AUTH_USER_NAME, user.get("name").getAsString());
JsonObject userDomain = user.get("domain").getAsJsonObject();
if (userDomain.get("id") != null) {
req.setAttribute(AUTH_USER_DOMAIN_ID, userDomain.get("id")
.getAsString());
}
if (userDomain.get("name") != null) {
req.setAttribute(AUTH_USER_DOMAIN_NAME, userDomain.get("name")
.getAsString());
}
}
// Roles
JsonArray roles = token.getAsJsonArray("roles");
if (roles != null) {
Iterator<JsonElement> it = roles.iterator();
while (it.hasNext()) {
JsonObject role = it.next().getAsJsonObject();
if (role.get("HP-IDM") != null) {
JsonObject hpIdm = role.get("HP-IDM").getAsJsonObject();
if (hpIdm.get("projectId") != null) {
tenants.append(",");
tenants.append(role.get("name").getAsString());
} else {
nonTenants.append(",");
nonTenants.append(role.get("name").getAsString());
}
}
}
}
String tenantRoles = (tenants.length() > 0) ? tenants.substring(1)
: tenants.toString();
String nonTenantRoles = (nonTenants.length() > 0) ? nonTenants
.substring(1) : nonTenants.toString();
if (!tenantRoles.equals("")) {
req.setAttribute(AUTH_ROLES, tenantRoles);
}
if (!nonTenantRoles.equals("")) {
req.setAttribute(AUTH_HP_IDM_ROLES, nonTenantRoles);
}
// Catalog
if (token.get("catalog") != null && appConfig.isIncludeCatalog()) {
JsonArray catalog = token.get("catalog").getAsJsonArray();
req.setAttribute(AUTH_SERVICE_CATALOG, catalog.toString());
}
}
private static void wrapRequestFromHttpV2Response(ServletRequest req,
String data) {
StringBuilder tenants = new StringBuilder();
StringBuilder nonTenants = new StringBuilder();
JsonParser jp = new JsonParser();
JsonObject access = jp.parse(data).getAsJsonObject().get("access")
.getAsJsonObject();
JsonObject token = access.get("token").getAsJsonObject();
// Tenant info
if (token.get("tenant") != null) {
JsonObject tenant = token.get("tenant").getAsJsonObject();
String id = tenant.get("id").getAsString();
String name = tenant.get("name").getAsString();
if (id != null)
req.setAttribute(AUTH_TENANT_ID, id);
if (name != null)
req.setAttribute(AUTH_TENANT_NAME, name);
}
// User info
if (access.get("user") != null) {
JsonObject user = access.get("user").getAsJsonObject();
String userId = user.get("id").getAsString();
String username = user.get("name").getAsString();
if (userId != null)
req.setAttribute(AUTH_USER_ID, userId);
if (username != null)
req.setAttribute(AUTH_USER_NAME, username);
// Roles
JsonArray roles = user.getAsJsonArray("roles");
if (roles != null) {
Iterator<JsonElement> it = roles.iterator();
while (it.hasNext()) {
JsonObject role = it.next().getAsJsonObject();
if (role.get("tenantId") != null) {
tenants.append(",");
tenants.append(role.get("name").getAsString());
} else {
nonTenants.append(",");
nonTenants.append(role.get("name").getAsString());
}
}
}
String tenantRoles = (tenants.length() > 0) ? tenants.substring(1)
: tenants.toString();
if (!tenantRoles.equals("")) {
req.setAttribute(AUTH_ROLES, tenantRoles);
}
String nonTenantRoles = (nonTenants.length() > 0) ? nonTenants
.substring(1) : nonTenants.toString();
if (!nonTenantRoles.equals("")) {
req.setAttribute(AUTH_HP_IDM_ROLES, nonTenantRoles);
}
}
// Service catalog
if (access.get("serviceCatalog") != null
&& appConfig.isIncludeCatalog()) {
JsonArray serviceCatalog = access.get("serviceCatalog")
.getAsJsonArray();
req.setAttribute(AUTH_SERVICE_CATALOG, serviceCatalog.toString());
}
}
public static ServletRequest wrapRequest(ServletRequest req, Object data) {
if (data == null) {
req.setAttribute(AUTH_IDENTITY_STATUS,
IdentityStatus.Invalid.toString());
logger.debug("Failed Authentication. Setting identity status header to Invalid");
}
req.setAttribute(AUTH_IDENTITY_STATUS,
IdentityStatus.Confirmed.toString());
//if (data instanceof String) {
wrapRequestFromHttpResponse(req, ((String) data));
//} else {
// wrapRequestFromThriftResponse(req, data);
//}
return req;
}
/*private static void wrapRequestFromThriftResponse(ServletRequest req,
Object data) {
StringBuilder tenants = new StringBuilder();
StringBuilder nonTenants = new StringBuilder();
if (data instanceof AuthResponseV2) {
AuthResponseV2 auth = (AuthResponseV2) data;
req.setAttribute(AUTH_TENANT_ID, auth.userInfo.tenantId);
req.setAttribute(AUTH_TENANT_NAME, auth.userInfo.tenantName);
req.setAttribute(AUTH_USER_ID, auth.userInfo.userId);
req.setAttribute(AUTH_USER_NAME, auth.userInfo.username);
getRoles(auth.userInfo.roles, tenants, nonTenants);
String tenantRoles = (tenants.length() > 0) ? tenants.substring(1)
: tenants.toString();
if (!tenantRoles.equals("")) {
req.setAttribute(AUTH_ROLES, tenantRoles);
}
String nonTenantRoles = (nonTenants.length() > 0) ? nonTenants
.substring(1) : nonTenants.toString();
if (!nonTenantRoles.equals("")) {
req.setAttribute(AUTH_HP_IDM_ROLES, nonTenantRoles);
}
if (auth.getServiceCatalog() != null) {
req.setAttribute(AUTH_SERVICE_CATALOG,
gson.toJson(auth.getServiceCatalog()));
}
} else if (data instanceof AuthResponseV3) {
AuthResponseV3 auth = (AuthResponseV3) data;
if (auth.getToken().getDomain() != null) {
req.setAttribute(AUTH_DOMAIN_ID, auth.getToken().getDomain()
.getId());
if (auth.getToken().getDomain().getName() != null) {
req.setAttribute(AUTH_DOMAIN_NAME, auth.getToken()
.getDomain().getName());
}
} else if (auth.getToken().getProject() != null) {
req.setAttribute(AUTH_PROJECT_ID, auth.getToken().getProject()
.getId());
req.setAttribute(AUTH_PROJECT_NAME, auth.getToken()
.getProject().getName());
req.setAttribute(AUTH_PROJECT_DOMAIN_ID, auth.getToken()
.getProject().getDomain().getId());
if (auth.getToken().getProject().getDomain().getName() != null) {
req.setAttribute(AUTH_PROJECT_DOMAIN_NAME, auth.getToken()
.getProject().getDomain().getName());
}
}
req.setAttribute(AUTH_USER_ID, auth.getToken().getUser()
.getUserId());
req.setAttribute(AUTH_USER_NAME, auth.getToken().getUser()
.getUsername());
req.setAttribute(AUTH_USER_DOMAIN_ID, auth.getToken().getUser()
.getDomain().getId());
if (auth.getToken().getUser().getDomain().getName() != null) {
req.setAttribute(AUTH_USER_DOMAIN_NAME, auth.getToken()
.getUser().getDomain().getName());
}
getRoles(auth.getToken().getRoles(), tenants, nonTenants);
String tenantRoles = (tenants.length() > 0) ? tenants.substring(1)
: tenants.toString();
String nonTenantRoles = (nonTenants.length() > 0) ? nonTenants
.substring(1) : nonTenants.toString();
if (!tenantRoles.equals("")) {
req.setAttribute(AUTH_ROLES, tenantRoles);
}
if (!nonTenantRoles.equals("")) {
req.setAttribute(AUTH_HP_IDM_ROLES, nonTenantRoles);
}
if (auth.getToken().getCatalog() != null) {
req.setAttribute(AUTH_SERVICE_CATALOG, gson
.toJson(buildServiceCatalogV3(auth.getToken()
.getCatalog())));
}
setDeprecatedHeaders(req, auth, tenantRoles);
}
} */
/*private static List<CatalogV3> buildServiceCatalogV3(
List<ServiceForCatalogV3> catalogs) {
List<CatalogV3> v3Catalogs = new ArrayList<CatalogV3>();
for (ServiceForCatalogV3 catalog : catalogs) {
CatalogV3 catalogv3 = new CatalogV3();
catalogv3.setId(catalog.getId());
catalogv3.setType(catalog.getType());
List<EndpointV3> endPoints = catalog.getEndpoints();
List<Properties> endPointsv3 = new ArrayList<Properties>();
for (EndpointV3 endPoint : endPoints) {
Properties endPointv3 = new Properties();
if (endPoint.getInterfaceName() != null) {
endPointv3.put("interface", endPoint.getInterfaceName());
}
if (endPoint.getEndpointId() != null) {
endPointv3.put("id", endPoint.getEndpointId());
}
if (endPoint.getServiceId() != null) {
endPointv3.put("service_id", endPoint.getServiceId());
}
if (endPoint.getRegion() != null) {
endPointv3.put("region", endPoint.getRegion());
}
if (endPoint.getUrl() != null) {
endPointv3.put("url", endPoint.getUrl());
}
endPointsv3.add(endPointv3);
}
catalogv3.setEndPoints(endPointsv3);
v3Catalogs.add(catalogv3);
}
return v3Catalogs;
} */
// Method will be removed after keystone removes the deprecated headers.
/*private static void setDeprecatedHeaders(ServletRequest req,
AuthResponseV3 auth, String tenantRoles) {
// Deprecated
req.setAttribute(AUTH_USER, auth.getToken().getUser().getUsername());
if (auth.getToken().getProject() != null) {
req.setAttribute(AUTH_TENANT_ID, auth.getToken().getProject()
.getId());
req.setAttribute(AUTH_TENANT_NAME, auth.getToken().getProject()
.getName());
req.setAttribute(AUTH_TENANT, auth.getToken().getProject()
.getName());
}
if (!tenantRoles.equals("")) {
req.setAttribute(AUTH_ROLE, tenantRoles);
}
} */
// Insert token into cache
public static void cacheToken(String token, Object auth) {
if (isCaching()) {
appConfig.getClient().put(token, auth);
/*try {
appConfig.getClient().putToken(token, auth);
} catch (TimeoutException e) {
logger.error("Error timeout setting memcache: " + token);
} catch (InterruptedException e) {
logger.error("Error memcache interrupted");
} catch (MemcachedException e) {
logger.error("Error memcache", e);
} */
}
}
// Get token from cache
public static Object getCachedToken(String token) {
if (isCaching()) {
long timeout = appConfig.getMemCacheTimeOut();
/*try {
return appConfig.getClient().getToken(token, timeout);
} catch (TimeoutException e) {
logger.error("Error timeout getting from memcache: " + token);
} catch (InterruptedException e) {
logger.error("Error memcache interrupted");
} catch (MemcachedException e) {
logger.error("Error memcache", e);
} */
}
return appConfig.getClient().getToken(token);
}
public static void pause(long pauseTime) {
try {
Thread.currentThread().sleep(pauseTime);
} catch (InterruptedException e) {
logger.debug("Thread is interrupted while sleeping before "
+ pauseTime + " seconds. ");
}
}
// Is caching enabled?
private static boolean isCaching() {
return appConfig.getClient() != null;
}
/* private static void getRoles(Object obj, StringBuilder tenants,
StringBuilder nonTenants) {
if (appConfig.getAuthVersion().equalsIgnoreCase("v2.0")) {
List<Role> roles = (List<Role>) obj;
for (Role role : roles) {
if (role.getTenantId() != null) {
tenants.append(",");
tenants.append(role.getName());
} else {
nonTenants.append(",");
nonTenants.append(role.getName());
}
}
} else {
List<V3Role> roles = (List<V3Role>) obj;
for (V3Role role : roles) {
if (role.getProjectId() != null) {
tenants.append(",");
tenants.append(role.getName());
} else {
nonTenants.append(",");
nonTenants.append(role.getName());
}
}
}
} */
}

View File

@ -0,0 +1,236 @@
package com.hp.csbu.cc.middleware;
import java.text.Format;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.SimpleTimeZone;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import com.hp.csbu.cc.security.cs.thrift.service.SigAuthRequest;
import com.hp.csbu.cc.security.cs.thrift.service.SignatureCredentials;
import static com.hp.csbu.cc.middleware.AuthConstants.SIGNATURE_METHOD;
public class HPS3Signer implements Signer {
private final Set<String> subResources = new HashSet<String>() {
{
add("acl");
add("logging");
add("torrent");
add("location");
add("requestPayment");
}
};
public SigAuthRequest sign(ServletRequest req, String serviceIds,
String endPointIds) {
String accessKeyId = null;
String signature = null;
String dataToSign = null;
if (req.getParameter("AWSAccessKeyId") != null) {
if (hasRequestExpired(req)) {
throw new SignatureBuilderException(
"Either signature is expired or expiration field is missing");
}
req.setAttribute("Date", req.getParameter("Expires"));
accessKeyId = req.getParameter("AWSAccessKeyId");
signature = req.getParameter("Signature");
} else {
Date d = null;
if (((HttpServletRequest) req).getHeader("X-Amz-Date") != null) {
d = parseDate(((HttpServletRequest) req)
.getHeader("X-Amz-Date"));
} else if (((HttpServletRequest) req).getHeader("Date") != null) {
d = parseDate(((HttpServletRequest) req).getHeader("Date"));
} else {
throw new SignatureBuilderException(
"Either date is missing or an invalid date is provided");
}
if (hasClockSkew(d)) {
throw new SignatureBuilderException(
"Date is invalid. Date is skewed by more than 15 mins");
}
String authorizationStr = ((HttpServletRequest) req)
.getHeader("Authorization");
authorizationStr = authorizationStr.substring(
authorizationStr.indexOf(" ")).trim();
int colonDelimeter = authorizationStr.lastIndexOf(":");
accessKeyId = authorizationStr.substring(0, colonDelimeter);
signature = authorizationStr.substring(colonDelimeter + 1);
}
dataToSign = getCanonicalString(req);
return getSignedRequest(dataToSign, accessKeyId, signature,
SIGNATURE_METHOD, serviceIds, endPointIds);
}
protected boolean hasClockSkew(Date d) {
if (d == null) {
// Invalid date
return true;
}
Date currentDate = new Date();
long currentTime = currentDate.getTime();
long epochTime = getUnixEpochTime();
long requestTime = d.getTime();
long delta = TimeUnit.MILLISECONDS.convert(15L, TimeUnit.MINUTES);
if (requestTime < epochTime) {
// Invalid date
return true;
}
if (Math.abs(requestTime - currentTime) > delta) {
// Invalid date
return true;
}
return false;
}
protected String getCanonicalString(ServletRequest req) {
HttpServletRequest request = ((HttpServletRequest) req);
StringBuffer canonicalStr = new StringBuffer();
Map<String, String> amzHeaders = new TreeMap<String, String>();
String contentMd5 = (request.getHeader("Content-MD5") == null) ? ""
: request.getHeader("Content-MD5");
String contentType = (request.getHeader("Content-Type") == null) ? ""
: request.getHeader("Content-Type");
String method = request.getMethod();
canonicalStr.append(method).append("\n").append(contentMd5)
.append("\n").append(contentType).append("\n");
Enumeration<String> headers = request.getHeaderNames();
while (headers.hasMoreElements()) {
String headerName = ((String) headers.nextElement()).toLowerCase();
if (headerName.startsWith("x-amz-")) {
Enumeration multiHeaderValues = request.getHeaders(headerName);
StringBuffer headerValues = new StringBuffer();
headerValues.append((String) multiHeaderValues.nextElement());
while (multiHeaderValues.hasMoreElements()) {
headerValues.append(",").append(
multiHeaderValues.nextElement());
}
amzHeaders.put(headerName, headerValues.toString());
}
}
if (amzHeaders.containsKey("X-Amz-Date")) {
canonicalStr.append("\n");
} else {
String date = (request.getHeader("Date") != null) ? (String) request
.getHeader("Date") : (String) request.getAttribute("Date");
canonicalStr.append(date).append("\n");
}
for (String key : amzHeaders.keySet()) {
canonicalStr.append(key).append(":").append(amzHeaders.get(key))
.append("\n");
}
String resource = getCanonicalResource(request);
canonicalStr.append(resource);
return canonicalStr.toString();
}
protected String getCanonicalResource(HttpServletRequest request) {
StringBuffer canonicalResource = new StringBuffer();
canonicalResource.append(request.getRequestURI());
String queryString = request.getQueryString();
if (queryString != null) {
canonicalResource.append(getCanonicalSubResource(queryString));
}
return canonicalResource.toString();
}
protected String getCanonicalSubResource(String queryString) {
String[] queryParams;
if (queryString.contains("&")) {
queryParams = queryString.split("&");
} else {
queryParams = new String[1];
queryParams[0] = queryString;
}
for (String param : queryParams) {
String paramName = param;
if (paramName.contains("=")) {
paramName = paramName.substring(0, paramName.indexOf("="));
}
if (subResources.contains(paramName)) {
return "?" + paramName;
}
}
return "";
}
protected long getUnixEpochTime() {
Format formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");
Date date;
try {
date = (Date) formatter.parseObject("01 Jan 1970 00:00:00 UTC");
} catch (ParseException e) {
return 0;
}
return date.getTime();
}
protected boolean hasRequestExpired(ServletRequest req) {
if (req.getParameter("Expires") == null) {
return true;
}
long expirationTime = new Long(req.getParameter("Expires"));
return expirationTime < (System.currentTimeMillis()/1000);
}
protected Date parseDate(String data) {
/* Currently date is parsed in RFC 822 format */
SimpleDateFormat df = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z");
df.setTimeZone(new SimpleTimeZone(0, "UTC"));
try {
return df.parse(data);
} catch (ParseException e) {
return null;
}
}
protected SigAuthRequest getSignedRequest(String dataToSign,
String accessKeyId, String signature, String signatureMethod,
String serviceIds, String endPointIds) {
try {
SignatureCredentials credentials = null;
Map<String, String> params = new HashMap<String, String>();
String tenantId = null;
String keyId = accessKeyId;
if (accessKeyId.contains(":")) {
String[] strArr = accessKeyId.split(":");
tenantId = strArr[0];
keyId = strArr[1];
}
credentials = new SignatureCredentials(keyId, "accesskey",
signatureMethod, dataToSign, signature);
//If tenantId is null, you get an unscoped token.
if (tenantId != null) {
params.put("tenantId", tenantId);
}
if (serviceIds != null) {
params.put("serviceIds", serviceIds);
}
if (endPointIds != null) {
params.put("endPointTemplateIds", endPointIds);
}
return new SigAuthRequest(credentials, params);
} catch (Exception e) {
throw new SignatureBuilderException(
"Exception building signature with given credentials");
}
}
}

View File

@ -0,0 +1,296 @@
package com.hp.csbu.cc.middleware;
import static com.hp.csbu.cc.middleware.AuthConstants.AUTH_SUBJECT_TOKEN;
import static com.hp.csbu.cc.middleware.AuthConstants.TOKEN;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.TimeZone;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHeader;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
//import com.hp.csbu.cc.security.cs.thrift.service.AuthResponse;
//import com.hp.csbu.cc.security.cs.thrift.service.SigAuthRequest;
public class HttpAuthClient implements AuthClient {
private static final String ACCESSKEY = "accesskey";
private static final String PASSWORD = "password";
private static final String SERVICE_IDS_PARAM = "serviceIds";
private static final String ENDPOINT_IDS_PARAM = "endpointIds";
private static final int DELTA_TIME_IN_SEC = 30;
private static SimpleDateFormat expiryFormat;
static {
expiryFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mmmmmm'Z'");
expiryFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
}
private final Config appConfig = Config.getInstance();
private HttpClient client;
private String adminToken;
private String adminTokenExpiry;
private URI uri;
public HttpAuthClient(HttpClient client, URI uri) {
this.client = client;
this.uri = uri;
}
@Override
public Object validateTokenForServiceEndpointV2(String token,
String serviceIds, String endpointIds, boolean includeCatalog)
throws ClientProtocolException {
String newUri = uri.toString() + "/v2.0/tokens/" + token;
return verifyUUIDToken(token, newUri, null, serviceIds, endpointIds);
}
@Override
public Object validateTokenForServiceEndpointV3(String token,
Map<String, String> inputParams) throws ClientProtocolException {
String newUri = uri.toString() + "/v3/auth/tokens/";
Header[] header = new Header[1];
header[0] = new BasicHeader(AUTH_SUBJECT_TOKEN, token);
String serviceIds = null;
String endpointIds = null;
if (inputParams.containsKey(SERVICE_IDS_PARAM))
serviceIds = inputParams.get(SERVICE_IDS_PARAM);
if (inputParams.containsKey(ENDPOINT_IDS_PARAM))
endpointIds = inputParams.get(ENDPOINT_IDS_PARAM);
return verifyUUIDToken(token, newUri, header, serviceIds, endpointIds);
}
private Object verifyUUIDToken(String token, String newUri,
Header[] header, String serviceIds, String endpointIds)
throws ClientProtocolException {
HttpResponse response = sendGet(newUri, header, serviceIds, endpointIds);
int code = response.getStatusLine().getStatusCode();
if (code == 404) {
throw new AuthException("Authorization failed for token: " + token);
}
if (code != 200) {
adminToken = null;
throw new AuthException("Failed to validate via HTTP " + code
+ " " +response.getStatusLine().getReasonPhrase());
}
return parseResponse(response);
}
private HttpResponse sendPost(String uri, StringEntity body)
throws ClientProtocolException {
HttpResponse response = null;
HttpPost post = new HttpPost(uri);
post.setHeader("Accept", "application/json");
post.setHeader("Content-Type", "application/json");
try {
post.setEntity(body);
response = client.execute(post);
int code = response.getStatusLine().getStatusCode();
if (!(code == 201 || code == 200 || code == 203)) {
adminToken = null;
throw new AuthException(
"Failed to authenticate admin credentials " + code
+ response.getStatusLine().getReasonPhrase());
}
} catch (IOException e) {
post.abort();
throw new ClientProtocolException(
"IO Exception during POST request ", e);
}
return response;
}
private HttpResponse sendGet(String newUri, Header[] headers,
String serviceIds, String endpointIds)
throws ClientProtocolException {
HttpResponse response = null;
HttpGet get = null;
boolean hasServiceIds = false;
if (serviceIds != null && !serviceIds.isEmpty()) {
newUri += "?HP-IDM-serviceId=" + serviceIds;
hasServiceIds = true;
}
if (endpointIds != null && !endpointIds.isEmpty()) {
newUri += hasServiceIds ? "&HP-IDM-endpointTemplateId="
+ endpointIds : "?HP-IDM-endpointTemplateId=" + endpointIds;
}
get = new HttpGet(newUri);
get.setHeader("Accept", "application/json");
get.setHeader("Content-Type", "application/json");
if (headers != null) {
for (Header header : headers) {
get.setHeader(header);
}
}
if (!appConfig.getAdminAuthMethod().isEmpty()) {
get.setHeader(new BasicHeader(TOKEN, getAdminToken()));
}
try {
response = client.execute(get);
} catch (IOException e) {
get.abort();
throw new ClientProtocolException(
"IO Exception during GET request ", e);
}
return response;
}
private String parseResponse(HttpResponse response) {
StringBuffer json = new StringBuffer();
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream instream;
try {
instream = entity.getContent();
BufferedReader reader = new BufferedReader(
new InputStreamReader(instream));
String line = reader.readLine();
while (line != null) {
json.append(line);
line = reader.readLine();
}
} catch (Exception e) {
throw new AuthException("Failed to parse Http Response ", e);
}
}
return json.toString();
}
private String getAdminToken() throws ClientProtocolException {
HttpResponse response;
String json;
JsonParser jp = new JsonParser();
if (adminTokenExpiry != null) {
if (isExpired(adminTokenExpiry)) {
adminToken = null;
}
}
if (adminToken == null) {
if (appConfig.getAuthVersion().equalsIgnoreCase("v2.0")) {
StringEntity params = getUnscopedV2AdminTokenRequest();
String authUri = uri + "/v2.0/tokens";
response = sendPost(authUri, params);
json = parseResponse(response);
JsonObject access = jp.parse(json).getAsJsonObject()
.get("access").getAsJsonObject();
JsonObject token = access.get("token").getAsJsonObject();
adminToken = token.get("id").getAsString();
adminTokenExpiry = token.get("expires").getAsString();
} else {
StringEntity params = getUnscopedV3AdminTokenRequest();
String authUri = uri + "/v3/auth/tokens";
response = sendPost(authUri, params);
adminToken = response.getFirstHeader(AUTH_SUBJECT_TOKEN)
.getValue();
json = parseResponse(response);
JsonObject token = jp.parse(json).getAsJsonObject()
.get("token").getAsJsonObject();
adminTokenExpiry = token.get("expires_at").getAsString();
}
}
return adminToken;
}
private StringEntity getUnscopedV2AdminTokenRequest() {
StringBuffer bfr = new StringBuffer();
if (appConfig.getAdminAuthMethod().equalsIgnoreCase(PASSWORD)) {
bfr.append("{\"auth\": {\"passwordCredentials\": {\"username\": \"");
bfr.append(appConfig.getAdminUser());
bfr.append("\",\"password\": \"");
bfr.append(appConfig.getAdminPassword());
if (appConfig.getAdminProject() != null && !appConfig.getAdminProject().isEmpty()) {
bfr.append("\"}, \"tenantId\": \"");
bfr.append(appConfig.getAdminProject());
bfr.append("\"}}");
} else {
bfr.append("\"}}}");
}
try {
return new StringEntity(bfr.toString());
} catch (UnsupportedEncodingException e) {
throw new AuthException("Invalid V2 authentication request "
+ e);
}
} else {
String msg = String.format("Admin auth method %s not supported",appConfig.getAdminAuthMethod());
throw new AuthException(msg);
}
}
private StringEntity getUnscopedV3AdminTokenRequest() {
StringBuffer bfr = new StringBuffer();
if (appConfig.getAdminAuthMethod().equalsIgnoreCase(PASSWORD)) {
bfr.append("{\"auth\": {\"identity\": {\"methods\": [\"password\"],\"password\": {\"user\": {\"name\": \"");
bfr.append(appConfig.getAdminUser());
bfr.append("\",\"password\": \"");
bfr.append(appConfig.getAdminPassword());
if (appConfig.getAdminProject() != null && !appConfig.getAdminProject().isEmpty()) {
bfr.append("\"},\"scope\": { \"project\": { \"id\": \"");
bfr.append(appConfig.getAdminProject());
bfr.append("\"}}}}}}");
} else {
bfr.append("\"}}}}}");
}
} else if (appConfig.getAdminAuthMethod().equalsIgnoreCase(ACCESSKEY)) {
bfr.append("{\"auth\": {\"identity\": {\"methods\": [\"accessKey\"], \"accessKey\": { \"accessKey\": \"");
bfr.append(appConfig.getAdminAccessKey());
bfr.append("\", \"secretKey\": \"");
bfr.append(appConfig.getAdminSecretKey());
if (appConfig.getAdminProject() != null && !appConfig.getAdminProject().isEmpty()) {
bfr.append("\"},\"scope\": { \"project\": { \"id\": \"");
bfr.append(appConfig.getAdminProject());
bfr.append("\"}}}}}");
} else {
bfr.append("\"}}}}");
}
} else {
String msg = String.format("Admin auth method %s not supported",appConfig.getAdminAuthMethod());
throw new AuthException(msg);
}
try {
return new StringEntity(bfr.toString());
} catch (UnsupportedEncodingException e) {
throw new AuthException("Invalid V3 authentication request " + e);
}
}
private boolean isExpired(String expires) {
Date tokenExpiryDate = null;
try {
tokenExpiryDate = expiryFormat.parse(expires);
} catch (ParseException e) {
return true;
}
Date current = new Date();
return tokenExpiryDate.getTime() < (current.getTime() + DELTA_TIME_IN_SEC * 1000);
}
public void reset() {
}
/* @Override
public AuthResponse validateSignature(SigAuthRequest request) {
// TODO Auto-generated method stub
return null;
}*/
}

View File

@ -0,0 +1,30 @@
package com.hp.csbu.cc.middleware;
import org.apache.commons.pool.impl.GenericObjectPool;
/**
* An HTTP factory.
*
* @author liemmn
*
*/
public class HttpClientFactory extends AuthClientFactory {
private HttpClientPoolFactory clientPool;
HttpClientFactory(String host, int port, int timeout, boolean clientAuth,
String keyStore, String keyPass, String trustStore,
String trustPass, String adminToken, int maxActive,
long timeBetweenEvictionRunsMillis, long minEvictableIdleTimeMillis) {
clientPool = new HttpClientPoolFactory(host, port, timeout, clientAuth,
keyStore, keyPass, trustStore, trustPass, adminToken,
maxActive, timeBetweenEvictionRunsMillis,
minEvictableIdleTimeMillis);
pool = new GenericObjectPool(clientPool);
}
@Override
public void shutdown() {
clientPool.shutDown();
super.shutdown();
}
}

View File

@ -0,0 +1,130 @@
package com.hp.csbu.cc.middleware;
import java.io.File;
import java.io.FileInputStream;
import java.net.URI;
import java.security.KeyStore;
import java.util.concurrent.TimeUnit;
import org.apache.commons.pool.BasePoolableObjectFactory;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.HttpParams;
/**
* A Http request pool factory. Based on Apache Commons Pool. Singleton.
* Note that the Apache HttpClient maintains its own connection pool and
* does not participate in Apache Commons pool' lifecycle other than creating
* HTTPRequests.
*
* @author liemmn
*
*/
public class HttpClientPoolFactory extends BasePoolableObjectFactory {
private URI uri;
private PoolingClientConnectionManager connMgr;
private HttpPoolCleaner cleaner;
private HttpClient client;
HttpClientPoolFactory(String host, int port, int timeout,
boolean clientAuth, String keyStore, String keyPass,
String trustStore, String trustPass, String adminToken,
int maxActive, long timeBetweenEvictionRunsMillis,
long minEvictableIdleTimeMillis) {
// Setup auth URL
String protocol = (port == 35357) ? "https://" : "http://";
String urlStr = protocol + host + ":" + port;
uri = URI.create(urlStr);
// Setup connection pool
SchemeRegistry schemeRegistry = new SchemeRegistry();
if (protocol.startsWith("https")) {
SSLSocketFactory sslf = sslFactory(keyStore, keyPass, trustStore,
trustPass, clientAuth);
schemeRegistry.register(new Scheme("https", port, sslf));
} else {
schemeRegistry.register(new Scheme("http", port, PlainSocketFactory
.getSocketFactory()));
}
connMgr = new PoolingClientConnectionManager(schemeRegistry,
minEvictableIdleTimeMillis, TimeUnit.MILLISECONDS);
connMgr.setMaxTotal(maxActive);
connMgr.setDefaultMaxPerRoute(maxActive);
// Http connection timeout
HttpParams params = new BasicHttpParams();
params.setParameter(CoreConnectionPNames.SO_TIMEOUT, timeout);
params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, timeout);
// Create a single client
client = new DefaultHttpClient(connMgr, params);
// Create and start the connection pool cleaner
cleaner = new HttpPoolCleaner(connMgr, timeBetweenEvictionRunsMillis,
minEvictableIdleTimeMillis);
new Thread(cleaner).start();
}
@Override
public Object makeObject() throws Exception {
return new HttpAuthClient(client, uri);
}
@Override
public void passivateObject(Object obj) throws Exception {
((HttpAuthClient) obj).reset();
}
@Override
public void destroyObject(Object obj) throws Exception {
((HttpAuthClient) obj).reset();
obj = null;
}
public void shutDown() {
// Shutdown all connections
connMgr.shutdown();
// Shutdown connection pool cleaner
cleaner.shutdown();
}
// get a socket factory
private static SSLSocketFactory sslFactory(String keyStore, String keyPass,
String trustStore, String trustPass, boolean clientAuth) {
try {
// keystore
KeyStore ks = null;
if (clientAuth) {
ks = KeyStore.getInstance("jks");
FileInputStream is1 = new FileInputStream(new File(keyStore));
try {
ks.load(is1, keyPass.toCharArray());
} finally {
is1.close();
}
}
// truststore
KeyStore ts = KeyStore.getInstance("jks");
FileInputStream is2 = new FileInputStream(
new File(trustStore));
try {
ts.load(is2, trustPass.toCharArray());
} finally {
is2.close();
}
SSLSocketFactory sslf = new SSLSocketFactory(ks, keyPass, ts);
return sslf;
} catch (Exception e) {
throw new AuthConnectionException(
"Failed to create SSLSocketFactory", e);
}
}
}

View File

@ -0,0 +1,56 @@
package com.hp.csbu.cc.middleware;
import java.util.concurrent.TimeUnit;
import org.apache.http.conn.ClientConnectionManager;
/**
* A runner to clean the connection pool! There should only be one!
*
* @author liemmn
*
*/
public class HttpPoolCleaner implements Runnable {
private final ClientConnectionManager connMgr;
private long timeBetweenEvictionRunsMillis, minEvictableIdleTimeMillis;
private volatile boolean shutdown;
public HttpPoolCleaner(ClientConnectionManager connMgr,
long timeBetweenEvictionRunsMillis, long minEvictableIdleTimeMillis) {
this.connMgr = connMgr;
this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
}
/**
* Start the cleaner.
*/
@Override
public void run() {
try {
while (!shutdown) {
synchronized (this) {
wait(timeBetweenEvictionRunsMillis);
// Close expired connections
connMgr.closeExpiredConnections();
// Close connections that have been idle longer than x sec
connMgr.closeIdleConnections(minEvictableIdleTimeMillis,
TimeUnit.MILLISECONDS);
}
}
} catch (InterruptedException ex) {
// terminate
}
}
/**
* Shutdown the cleaner.
*/
public void shutdown() {
shutdown = true;
synchronized (this) {
notifyAll();
}
}
}

View File

@ -0,0 +1,283 @@
package com.hp.csbu.cc.middleware;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.SimpleTimeZone;
import java.util.concurrent.TimeoutException;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.XMemcachedClientBuilder;
import net.rubyeye.xmemcached.exception.MemcachedException;
import net.rubyeye.xmemcached.utils.AddrUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//import com.hp.csbu.cc.security.cs.thrift.service.AuthResponseV2;
//import com.hp.csbu.cc.security.cs.thrift.service.AuthResponseV3;
/**
* An internal class to allow encryption and decryption of validated tokens
* stored in memcache.
*
* @author liemmn
*
*/
public class MemcacheCrypt {
// GMT date format for expiration time stamp in token
static SimpleDateFormat expiryFormat;
static {
expiryFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
Calendar cal = Calendar.getInstance(new SimpleTimeZone(0, "GMT"));
expiryFormat.setCalendar(cal);
}
// character set to use for converting between chars and bytes
private static final String CHARSET_NAME = "UTF-8";
// message digest algorithm
private static final String DIGEST_ALGORITHM = "SHA-256";
// key algorithm
private static final String KEY_ALGORITHM = "AES";
// cipher algorithm
private static final String CIPHER_ALGORITHM = KEY_ALGORITHM
+ "/CBC/PKCS5Padding";
// Thee password
private static final String PASSWORD = "G0n30ffTehC11ff!";
// Wrapped memcache client instance
//private MemcachedClient client;
private TokenCache client;
// Cache value to be encrypted or not
private boolean isEncrypted;
// Thee faithful logger
private static final Logger logger = LoggerFactory
.getLogger(MemcacheCrypt.class);
/**
* Construct a memcache client instance.
*
* @param cacheHosts
* List of memcache servers
* @param isEncrypted
* Uses encryption or not
* @throws IOException
*/
public MemcacheCrypt(String cacheHosts, boolean isEncrypted)
throws IOException {
XMemcachedClientBuilder builder = new XMemcachedClientBuilder(
AddrUtil.getAddresses(cacheHosts));
this.client = builder.build();
this.isEncrypted = isEncrypted;
}
/**
* Shutdown this client instance.
*
* @throws IOException
*/
public void shutdown() throws IOException {
client.shutdown();
}
/**
* Store given token into memcache.
*
* @param token
* Token
* @param auth
* Token info
* @throws TimeoutException
* @throws InterruptedException
* @throws MemcachedException
*/
public void putToken(String token, Object auth) throws TimeoutException,
InterruptedException, MemcachedException {
String expires = null;
/* if (auth instanceof AuthResponseV2) {
expires = ((AuthResponseV2) auth).getTokenInfo().getExpires();
} else {
expires = ((AuthResponseV3) auth).getToken().getExpires_at();
} */
if (isEncrypted) {
auth = encrypt(token, PASSWORD, auth);
}
client.set("tokens/" + token, expireFromNow(expires), auth);
}
/**
* Get a token, or null if no token found in cache.
*
* @param token
* Token
* @param timeout
* Timeout waiting to get token
* @return Token info
* @throws TimeoutException
* @throws InterruptedException
* @throws MemcachedException
*/
public Object getToken(String token, long timeout) throws TimeoutException,
InterruptedException, MemcachedException {
Object o = client.get("tokens/" + token, timeout);
/*if (o instanceof AuthResponseV2) {
return (AuthResponseV2) o;
} else if (o instanceof AuthResponseV3) {
return (AuthResponseV3) o;
} else if (o instanceof byte[]) {
return decrypt(token, PASSWORD, (byte[]) o);
}
*/
if (o instanceof byte[]) {
return decrypt(token, PASSWORD, (byte[]) o);
}
return null;
}
// Test method... Don't use!
void setEncrypted(boolean isEncrypted) {
this.isEncrypted = isEncrypted;
}
// Expiration from now in seconds
private int expireFromNow(String expires) {
Date tokenDate = null;
try {
tokenDate = expiryFormat.parse(expires);
} catch (ParseException e) {
logger.error("Error parsing token expiration: " + expires);
}
Date current = new Date();
return (int) ((tokenDate.getTime() - current.getTime()) / 1000);
}
/**
* Encrypts the given token information
*
* @param token
* Token
* @param password
* Password used for encryption/decryption
* @param auth
* Token info to encrypt
* @return Encrypted token info
*/
static byte[] encrypt(final String token, final String password,
final Object tokenData) {
byte[] encryptedAuth = null;
ByteArrayOutputStream baos = null;
try {
// Compute key and iv from token and password
Secret secret = genSecret(token, password);
// Serialize the token info
baos = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(baos);
/* if (tokenData instanceof AuthResponseV2) {
os.writeObject((AuthResponseV2) tokenData);
} else {
os.writeObject((AuthResponseV3) tokenData);
}*/
byte[] data = baos.toByteArray();
// Performs 128-AES encryption
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(secret.key,
KEY_ALGORITHM), new IvParameterSpec(secret.iv));
encryptedAuth = cipher.doFinal(data);
} catch (Exception e) {
throw new EncryptionException("Failed to encrypt " + token, e);
} finally {
if (baos != null)
try {
baos.close();
} catch (IOException e) {
}
}
return encryptedAuth;
}
/**
* Decrypts the given token info data.
*
* @param token
* Token
* @param password
* Password used for encryption/decryption.
* @param data
* Token info data
* @return Token info
*/
static Object decrypt(final String token, final String password,
final byte[] data) {
ByteArrayInputStream bais = null;
Object auth = null;
try {
// Compute key and iv from token and password
Secret secret = genSecret(token, password);
// Performs 128-AES decryption
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(secret.key,
KEY_ALGORITHM), new IvParameterSpec(secret.iv));
byte[] decryptedAuth = cipher.doFinal(data);
// Deserialize the token info
bais = new ByteArrayInputStream(decryptedAuth);
ObjectInputStream ois = new ObjectInputStream(bais);
auth = ois.readObject();
bais.close();
} catch (Exception e) {
throw new DecryptionException("Failed to decrypt " + token, e);
} finally {
if (bais != null)
try {
bais.close();
} catch (IOException e) {
}
}
return auth;
}
// Compute key and iv from token and password
private static Secret genSecret(final String token, final String password)
throws UnsupportedEncodingException, NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance(DIGEST_ALGORITHM);
byte[] seed = (token + password).getBytes(CHARSET_NAME);
byte[] pw = md.digest(seed);
Secret secret = new Secret();
System.arraycopy(pw, 0, secret.key, 0, 16);
System.arraycopy(pw, 16, secret.iv, 0, 16);
Arrays.fill(pw, (byte) 0x00);
return secret;
}
// Data object to hold the key and iv for encryption/decryption
private static final class Secret {
byte[] key = new byte[16];
byte[] iv = new byte[16];
}
}

View File

@ -0,0 +1,95 @@
package com.hp.csbu.cc.middleware;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.hp.csbu.cc.middleware.AuthConstants.IdentityStatus;
import com.hp.csbu.cc.security.cs.thrift.service.AuthResponse;
import com.hp.csbu.cc.security.cs.thrift.service.SigAuthRequest;
public class S3SignatureAuth implements Filter, AuthConstants {
private final Config appConfig = Config.getInstance();
private FilterConfig filterConfig;
// Thee faithful logger
private static final Logger logger = LoggerFactory
.getLogger(S3SignatureAuth.class);
private static final String SIGNATURE_NOT_FOUND = "Invalid Credentials: Token or Signature not found in the request";
@Override
public void destroy() {
FilterUtils.destroyFilter();
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
AuthResponse auth = null;
if (!appConfig.isInitialized()) {
appConfig.initialize(filterConfig);
}
// Flow has reached here by setting DelayAuthDecision.
// Check if the token validation has failed and then continue to
// signatue validation.
if (req.getAttribute(AUTH_IDENTITY_STATUS).equals(
IdentityStatus.Invalid.toString())) {
HPS3Signer s3Signer = new HPS3Signer();
if (isS3Request(req)) {
AuthClient client = null;
try {
SigAuthRequest signedRequest = s3Signer.sign(req,
appConfig.getServiceIds(),
appConfig.getEndpointIds());
client = appConfig.getFactory().getClient();
auth = client.validateSignature(signedRequest);
// Return to connection pool for re-use
appConfig.getFactory().recycle(client);
} catch (Exception ex) {
if (client != null)
appConfig.getFactory().discard(client);
SignatureExceptionHandler handler = ExceptionHandlerUtil
.lookUpSignatureException(ex);
handler.onException(ex, resp);
}
} else {
logger.error(HttpServletResponse.SC_UNAUTHORIZED
+ SIGNATURE_NOT_FOUND);
((HttpServletResponse) resp).sendError(
HttpServletResponse.SC_UNAUTHORIZED,
SIGNATURE_NOT_FOUND);
}
req = FilterUtils.wrapRequest(req, auth);
}
// Continue in the filter chain as DelayAuthDecision has been set.
chain.doFilter(req, resp);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
private boolean isS3Request(ServletRequest req) {
if (((HttpServletRequest) req).getHeader("Authorization") != null
|| ((req.getParameter("AWSAccessKeyId")) != null && req
.getParameter("Signature") != null)) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,15 @@
package com.hp.csbu.cc.middleware;
public class SignatureBuilderException extends RuntimeException {
private static final long serialVersionUID = -2643382825421961020L;
public SignatureBuilderException(String msg) {
super(msg);
}
public SignatureBuilderException(String msg, Exception e) {
super(msg, e);
}
}

View File

@ -0,0 +1,99 @@
package com.hp.csbu.cc.middleware;
import java.io.IOException;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
//import org.apache.thrift.TException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//import com.hp.csbu.cc.security.cs.thrift.service.ResourceException;
public enum SignatureExceptionHandler {
AuthConnectionException {
@Override
public void onException(Exception e, ServletResponse resp) {
AuthConnectionException ae = (AuthConnectionException) e;
logger.error(ae.getMessage() + " " + ae);
try {
((HttpServletResponse) resp).sendError(
HttpServletResponse.SC_UNAUTHORIZED,
ExceptionHandlerUtil.getStatusText(HttpServletResponse.SC_UNAUTHORIZED));
} catch (IOException ie) {
logger.debug("Error in writing the HTTP response "
+ ie.getMessage() + " " + ie);
}
}
},
TException {
@Override
public void onException(Exception e, ServletResponse resp) {
// TException t = (TException) e;
//logger.error("Thrift Exception " + t.getMessage() + " " + t);
try {
((HttpServletResponse) resp).sendError(
HttpServletResponse.SC_UNAUTHORIZED,
ExceptionHandlerUtil.getStatusText(HttpServletResponse.SC_UNAUTHORIZED));
} catch (IOException ie) {
logger.debug("Error in writing the HTTP response "
+ ie.getMessage() + " " + ie);
}
}
},
SignatureBuilderException {
@Override
public void onException(Exception e, ServletResponse resp) {
SignatureBuilderException sbe = (SignatureBuilderException) e;
logger.error(sbe.getMessage() + " " + sbe);
try {
((HttpServletResponse) resp).sendError(
HttpServletResponse.SC_UNAUTHORIZED,
ExceptionHandlerUtil.getStatusText(HttpServletResponse.SC_UNAUTHORIZED));
} catch (IOException ie) {
logger.debug("Error in writing the HTTP response "
+ ie.getMessage() + " " + ie);
}
}
},
AuthException {
@Override
public void onException(Exception e, ServletResponse resp) {
AuthException ae = (AuthException) e;
logger.error(ae.getMessage() + " " + ae);
try {
((HttpServletResponse) resp).sendError(
HttpServletResponse.SC_UNAUTHORIZED,
ExceptionHandlerUtil.getStatusText(HttpServletResponse.SC_UNAUTHORIZED));
} catch (IOException ie) {
logger.debug("Error in writing the HTTP response "
+ ie.getMessage() + " " + ie);
}
}
};
/*ResourceException {
@Override
public void onException(Exception e, ServletResponse resp) {
// ResourceException re = (ResourceException) e;
logger.error(HttpServletResponse.SC_UNAUTHORIZED
+ " " + re);
String statusText = re.getDetail();
if (statusText == null || statusText.isEmpty()) {
statusText = ExceptionHandlerUtil.getStatusText(HttpServletResponse.SC_UNAUTHORIZED);
}
try {
((HttpServletResponse) resp).sendError(
HttpServletResponse.SC_UNAUTHORIZED, statusText);
} catch (IOException ie) {
logger.debug("Error in writing the HTTP response "
+ ie.getMessage() + " " + ie);
}
}
}; */
final Logger logger = LoggerFactory.getLogger(SignatureExceptionHandler.class);
abstract void onException(Exception e, ServletResponse resp);
}

View File

@ -0,0 +1,5 @@
package com.hp.csbu.cc.middleware;
public interface Signer {
}

View File

@ -0,0 +1,68 @@
package com.hp.csbu.cc.middleware;
import java.util.Map;
import org.apache.thrift.TException;
import com.hp.csbu.cc.security.cs.thrift.service.AuthResponse;
//import com.hp.csbu.cc.security.cs.thrift.service.AuthResponseV2;
//import com.hp.csbu.cc.security.cs.thrift.service.AuthResponseV3;
import com.hp.csbu.cc.security.cs.thrift.service.CsThriftService.Client;
import com.hp.csbu.cc.security.cs.thrift.service.ResourceException;
import com.hp.csbu.cc.security.cs.thrift.service.SigAuthRequest;
/**
* An AuthClient adapter for Thrift.
*
* @author liemmn
*
*/
public class ThriftAuthClient implements AuthClient {
private Client thrift;
public ThriftAuthClient(Client client) {
this.thrift = client;
}
public void close() {
thrift.getInputProtocol().getTransport().close();
thrift.getOutputProtocol().getTransport().close();
thrift = null;
}
@Override
public AuthResponse validateSignature(SigAuthRequest request)
throws ResourceException, TException {
return thrift.validateSignature(request);
}
@Override
/*public AuthResponseV2 validateTokenForServiceEndpointV2(String token,
String serviceIds, String endpointIds, boolean includeCatalog)
throws ResourceException, TException {
return thrift.validateTokenForEndpointWithCatalog(token, null,
serviceIds, endpointIds, includeCatalog);
} */
public Object validateTokenForServiceEndpointV2(String token,
String serviceIds, String endpointIds, boolean includeCatalog)
throws ResourceException, TException {
return null;
}
@Override
/*public AuthResponseV3 validateTokenForServiceEndpointV3(String token,
Map<String, String> inputParams)
throws ResourceException, TException {
return thrift.validateTokenApiForEndpoint(token, inputParams);
} */
public Object validateTokenForServiceEndpointV3(String token,
Map<String, String> inputParams)
throws ResourceException, TException {
return null;
}
}

View File

@ -0,0 +1,19 @@
package com.hp.csbu.cc.middleware;
import org.apache.commons.pool.impl.GenericObjectPool;
/**
* A Thrift factory.
*
* @author liemmn
*
*/
public class ThriftClientFactory extends AuthClientFactory {
ThriftClientFactory(String host, int port,
int timeout, boolean clientAuth, String keyStore, String keyPass,
String trustStore, String trustPass) {
pool = new GenericObjectPool(new ThriftClientPoolFactory(host, port,
timeout, clientAuth, keyStore, keyPass, trustStore, trustPass));
}
}

View File

@ -0,0 +1,71 @@
package com.hp.csbu.cc.middleware;
import org.apache.commons.pool.BasePoolableObjectFactory;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSSLTransportFactory;
import org.apache.thrift.transport.TSocket;
import com.hp.csbu.cc.security.cs.thrift.service.CsThriftService;
/**
* ThriftConnection pool factory. Based on Apache Commons Pool.
*
* @author liemmn
*
*/
public class ThriftClientPoolFactory extends BasePoolableObjectFactory {
private static final String PROTOCOL = "TLS";
private static final String[] CIPHER_SUITES = new String[] {
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
"SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_RSA_WITH_AES_128_CBC_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
"SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA" };
private String host;
private int port;
private int timeout;
private boolean clientAuth;
private String keyStore;
private String keyPass;
private String trustStore;
private String trustPass;
public ThriftClientPoolFactory(String host, int port, int timeout,
boolean clientAuth, String keyStore, String keyPass,
String trustStore, String trustPass) {
this.host = host;
this.port = port;
this.timeout = timeout;
this.clientAuth = clientAuth;
this.keyStore = keyStore;
this.keyPass = keyPass;
this.trustStore = trustStore;
this.trustPass = trustPass;
}
@Override
public AuthClient makeObject() {
TSSLTransportFactory.TSSLTransportParameters params = new TSSLTransportFactory.TSSLTransportParameters(
PROTOCOL, CIPHER_SUITES, clientAuth);
params.setKeyStore(keyStore, keyPass);
params.setTrustStore(trustStore, trustPass);
try {
TSocket clientSocket = TSSLTransportFactory.getClientSocket(host,
port, timeout, params);
TProtocol proto = new TCompactProtocol(clientSocket);
return new ThriftAuthClient(new CsThriftService.Client(proto));
} catch (Exception e) {
throw new AuthConnectionException("Failed to open socket " + e.getMessage(), e);
}
}
@Override
public void destroyObject(Object o) {
((ThriftAuthClient) o).close();
o = null;
}
}

View File

@ -0,0 +1,185 @@
package com.hp.csbu.cc.middleware;
import java.io.IOException;
import org.apache.http.client.ClientProtocolException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.thrift.transport.TTransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A token-based authentication filter. This filter uses Thrift protocol to
* communicate with the CS server. The token to validate is set via the header
* {@link #TOKEN}.
* <p>
* A token is required to validate. However, if no token is presented, the
* filter will set the {@link #AUTH_IDENTITY_STATUS} request parameter to
* <code>Invalid</code> and let any other filter downstream to decide what to
* do. For instance, if a downstream filter knows how to deal with signature
* rather than tokens, then it will go ahead and validate with signatures.
* <p>
* Upon successful validation, all the Auth request parameters will be
* populated, including information such as tenant, user and user roles, and
* passed down to the next filter downstream.
* <p>
* Upon unsuccessful validation, this filter will terminate the request by
* returning a 401 (unauthorized).
*
* @author liemmn
*
*/
public class TokenAuth implements Filter, AuthConstants {
private static final String TOKEN_NOTFOUND = "Bad Request: Token not found in the request";
private static final String SERVICE_IDS_PARAM = "serviceIds";
private static final String ENDPOINT_IDS_PARAM = "endpointIds";
private static final String SERVICE_CATALOG_PARAM = "includeCatalog";
private static final String API_VERSION_PARAM = "apiVersion";
private final Config appConfig = Config.getInstance();
private FilterConfig filterConfig;
// Thee faithful logger
private static final Logger logger = LoggerFactory
.getLogger(TokenAuth.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
/**
* {@inheritDoc}
*/
public void destroy() {
FilterUtils.destroyFilter();
}
/**
* {@inheritDoc}
*/
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
Object auth = null;
int numberOfTries = 0;
if (!appConfig.isInitialized()) {
appConfig.initialize(filterConfig);
}
int retries = appConfig.getRetries();
long pauseTime = appConfig.getPauseTime();
AuthClientFactory factory = appConfig.getFactory();
// Extract credential
String token = ((HttpServletRequest) req).getHeader(TOKEN);
if (token == null) {
if (!appConfig.isDelayAuthDecision()) {
logger.error(HttpServletResponse.SC_UNAUTHORIZED
+ " No token found.");
((HttpServletResponse) resp).sendError(
HttpServletResponse.SC_UNAUTHORIZED, TOKEN_NOTFOUND);
return;
} else {
logger.info("No token found...Skipping");
}
} else {
// Retrieve from cache
auth = FilterUtils.getCachedToken(token);
if (auth == null) {
// Validate credential
AuthClient client = null;
do {
try {
client = factory.getClient();
if (appConfig.getAuthVersion().equalsIgnoreCase("v2.0")) {
auth = client.validateTokenForServiceEndpointV2(token, appConfig.getServiceIds(),
appConfig.getEndpointIds(), appConfig.isIncludeCatalog());
} else {
auth = client.validateTokenForServiceEndpointV3(token, getInputParams());
}
// Cache token
FilterUtils.cacheToken(token, auth);
// Return to connection pool for re-use
factory.recycle(client);
logger.debug("Successful Authentication");
break;
} catch (TTransportException t) {
if (client != null)
factory.discard(client);
if (numberOfTries < retries) {
FilterUtils.pause(pauseTime);
logger.debug("Retrying connection after "
+ pauseTime + " seconds.");
numberOfTries++;
continue;
} else {
TokenExceptionHandler handler = TokenExceptionHandler
.valueOf("TException");
handler.onException(t, resp, token);
}
return;
} catch (ClientProtocolException c) {
if (client != null)
factory.discard(client);
if (numberOfTries < retries) {
FilterUtils.pause(pauseTime);
logger.debug("Retrying connection after "
+ pauseTime + " seconds.");
numberOfTries++;
continue;
} else {
TokenExceptionHandler handler = TokenExceptionHandler
.valueOf("ClientProtocolException");
handler.onException(c, resp, token);
}
return;
}catch (Exception ex) {
if (client != null)
factory.recycle(client);
TokenExceptionHandler handler = ExceptionHandlerUtil
.lookUpTokenException(ex);
handler.onException(ex, resp, token);
return;
}
} while (numberOfTries <= retries);
} else {
// Got a cached token!
logger.debug("Got cached token: " + token);
}
}
req = FilterUtils.wrapRequest(req, auth);
logger.debug("TokenAuth: Forwarding down stream to next filter/servlet");
// Forward downstream...
chain.doFilter(req, resp);
}
private Map<String, String> getInputParams() {
Map<String, String> inputParams = new HashMap<String, String>();
if (appConfig.getServiceIds() != null) {
inputParams.put(SERVICE_IDS_PARAM, appConfig.getServiceIds());
}
if (appConfig.getEndpointIds() != null) {
inputParams.put(ENDPOINT_IDS_PARAM, appConfig.getEndpointIds());
}
inputParams.put(SERVICE_CATALOG_PARAM, String.valueOf(appConfig.isIncludeCatalog()));
inputParams.put(API_VERSION_PARAM, appConfig.getAuthVersion());
return inputParams;
}
}

View File

@ -0,0 +1,22 @@
package com.hp.csbu.cc.middleware;
import org.apache.commons.collections4.map.PassiveExpiringMap;
/**
* Created by johnderr on 6/9/14.
*/
public class TokenCache<K,V> {
private PassiveExpiringMap<K,V> map;
public TokenCache(Long timeToExpire) {
map = new PassiveExpiringMap<>(timeToExpire);
}
public V getToken(K key) {
return map.get(key);
}
public void put(K key, V value) {
map.put(key,value);
}
}

View File

@ -0,0 +1,108 @@
package com.hp.csbu.cc.middleware;
import java.io.IOException;
import org.apache.http.client.ClientProtocolException;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.thrift.TException;
//import com.hp.csbu.cc.security.cs.thrift.service.ResourceException;
public enum TokenExceptionHandler {
AuthConnectionException {
@Override
public void onException(Exception e, ServletResponse resp, String token) {
AuthConnectionException ae = (AuthConnectionException) e;
logger.error(ae.getMessage() + " " + ae);
try {
((HttpServletResponse) resp).sendError(
HttpServletResponse.SC_UNAUTHORIZED,
ExceptionHandlerUtil.getStatusText(HttpServletResponse.SC_UNAUTHORIZED)
+ " " + token);
} catch (IOException ie) {
logger.debug("Error in writing the HTTP response "
+ ie.getMessage() + " " + ie);
}
}
},
TException {
@Override
public void onException(Exception e, ServletResponse resp, String token) {
TException t = (TException) e;
logger.error("Thrift Exception " + t.getMessage() + " " + t);
try {
((HttpServletResponse) resp).sendError(
HttpServletResponse.SC_UNAUTHORIZED,
ExceptionHandlerUtil.getStatusText(HttpServletResponse.SC_UNAUTHORIZED)
+ " " + token);
} catch (IOException ie) {
logger.debug("Error in writing the HTTP response "
+ ie.getMessage() + " " + ie);
}
}
},
ClientProtocolException {
@Override
public void onException(Exception e, ServletResponse resp, String token) {
ClientProtocolException t = (ClientProtocolException) e;
logger.error("Http Client Exception " + t.getMessage() + " " + t);
try {
((HttpServletResponse) resp).sendError(
HttpServletResponse.SC_UNAUTHORIZED,
ExceptionHandlerUtil.getStatusText(HttpServletResponse.SC_UNAUTHORIZED)
+ " " + token);
} catch (IOException ie) {
logger.debug("Error in writing the HTTP response "
+ ie.getMessage() + " " + ie);
}
}
},
/*ResourceException {
@Override
public void onException(Exception e, ServletResponse resp, String token) {
ResourceException re = (ResourceException) e;
logger.error(HttpServletResponse.SC_UNAUTHORIZED + " " + token
+ " " + re);
String statusText = re.getDetail();
if (statusText == null || statusText.isEmpty()) {
statusText = ExceptionHandlerUtil.getStatusText(HttpServletResponse.SC_UNAUTHORIZED);
}
try {
((HttpServletResponse) resp).sendError(
HttpServletResponse.SC_UNAUTHORIZED, statusText + " "
+ token);
} catch (IOException ie) {
logger.debug("Error in writing the HTTP response "
+ ie.getMessage() + " " + ie);
}
}
},*/
AuthException {
@Override
public void onException(Exception e, ServletResponse resp, String token) {
AuthException ae = (AuthException) e;
logger.error(ae.getMessage() + " " + ae);
String statusText = ae.getMessage();
if (statusText == null || statusText.isEmpty()) {
statusText = ExceptionHandlerUtil.getStatusText(HttpServletResponse.SC_UNAUTHORIZED);
}
try {
((HttpServletResponse) resp).sendError(
HttpServletResponse.SC_UNAUTHORIZED,
statusText + " " + token);
} catch (IOException ie) {
logger.debug("Error in writing the HTTP response "
+ ie.getMessage() + " " + ie);
}
}
};
final Logger logger = LoggerFactory.getLogger(TokenExceptionHandler.class);
abstract void onException(Exception e, ServletResponse resp, String token);
}

View File

@ -34,7 +34,7 @@ import org.slf4j.LoggerFactory;
import com.hpcloud.mon.resource.exception.Exceptions;
import com.hpcloud.mon.resource.exception.Exceptions.FaultType;
import com.hp.csbu.cc.middleware.ExceptionHandler.*;
//import com.hp.csbu.cc.middleware.ExceptionHandler.*;
/**
* Authenticates requests using header information from the CsMiddleware. Provides the X-TENANT-ID