diff options
| author | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2019-09-13 13:23:21 +0200 | 
|---|---|---|
| committer | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2019-09-13 13:23:21 +0200 | 
| commit | 5780d9aa93fcd363584046fb404c63b909faebdb (patch) | |
| tree | 6257d77a34fffb342a9318fbc845a60ed47b1c45 /eaaf_core_utils/src | |
| parent | 8883fd1c0efa08fe0a73a11a1c8986fa3ea72753 (diff) | |
| download | EAAF-Components-5780d9aa93fcd363584046fb404c63b909faebdb.tar.gz EAAF-Components-5780d9aa93fcd363584046fb404c63b909faebdb.tar.bz2 EAAF-Components-5780d9aa93fcd363584046fb404c63b909faebdb.zip | |
add SimpleStatusMessager.java that only perform String formatting
add SSL Client authentication and http basic authentication to HttpClientFactory.java
Diffstat (limited to 'eaaf_core_utils/src')
| -rw-r--r-- | eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/logging/SimpleStatusMessager.java | 44 | ||||
| -rw-r--r-- | eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HttpClientFactory.java | 240 | 
2 files changed, 264 insertions, 20 deletions
| diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/logging/SimpleStatusMessager.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/logging/SimpleStatusMessager.java new file mode 100644 index 00000000..d36c79b9 --- /dev/null +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/logging/SimpleStatusMessager.java @@ -0,0 +1,44 @@ +package at.gv.egiz.eaaf.core.impl.logging; + +import java.text.MessageFormat; + +import at.gv.egiz.eaaf.core.api.IStatusMessenger; + +/** + * Simple {@link IStatusMessenger} implementation that formats messages by using {@link MessageFormat}  + *  + * @author tlenz + * + */ +public class SimpleStatusMessager implements IStatusMessenger { + +	private static final String NOTSUPPORTED = "Error response-codes not supported"; +	private static final String NULLMESSAGE = "No error-message provided"; +	 +	@Override +	public String getMessage(String messageId, Object[] parameters) {		 +		return getMessageWithoutDefault(messageId, parameters); +		 +	} + +	@Override +	public String getMessageWithoutDefault(String messageId, Object[] parameters) { +		if (messageId != null) { +			return MessageFormat.format(messageId, parameters); +			 +		} +		 +		return NULLMESSAGE; +	} + +	@Override +	public String getResponseErrorCode(Throwable throwable) { +		return NOTSUPPORTED; +	} + +	@Override +	public String mapInternalErrorToExternalError(String intErrorCode) { +		return NOTSUPPORTED; +	} + +} diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HttpClientFactory.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HttpClientFactory.java index a141d92d..73f2c518 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HttpClientFactory.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HttpClientFactory.java @@ -1,31 +1,46 @@  package at.gv.egiz.eaaf.core.impl.utils; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException;  import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException;  import javax.annotation.PostConstruct;  import javax.net.ssl.HostnameVerifier;  import javax.net.ssl.SSLContext; +import org.apache.commons.lang3.StringUtils;  import org.apache.http.HttpRequest;  import org.apache.http.HttpResponse;  import org.apache.http.ProtocolException; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider;  import org.apache.http.client.RedirectStrategy;  import org.apache.http.client.config.RequestConfig;  import org.apache.http.client.methods.HttpUriRequest;  import org.apache.http.conn.socket.LayeredConnectionSocketFactory;  import org.apache.http.conn.ssl.NoopHostnameVerifier;  import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.client.BasicCredentialsProvider;  import org.apache.http.impl.client.CloseableHttpClient;  import org.apache.http.impl.client.DefaultRedirectStrategy;  import org.apache.http.impl.client.HttpClientBuilder;  import org.apache.http.impl.client.HttpClients;  import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;  import org.apache.http.protocol.HttpContext; +import org.apache.http.ssl.SSLContexts;  import org.slf4j.Logger;  import org.slf4j.LoggerFactory;  import org.springframework.beans.factory.annotation.Autowired;  import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.exceptions.EAAFConfigurationException;  public class HttpClientFactory implements IHttpClientFactory {  	private static final Logger log = LoggerFactory.getLogger(HttpClientFactory.class);	 @@ -39,6 +54,13 @@ public class HttpClientFactory implements IHttpClientFactory {  	public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_REQUEST = "client.http.connection.timeout.request";  	public static final String PROP_CONFIG_CLIENT_HTTP_SSL_HOSTNAMEVERIFIER_TRUSTALL = "client.http.ssl.hostnameverifier.trustall"; +	public static final String PROP_CONFIG_CLIENT_MODE = "client.authmode"; +	public static final String PROP_CONFIG_CLIENT_AUTH_HTTP_USERNAME = "client.auth.http.username"; +	public static final String PROP_CONFIG_CLIENT_AUTH_HTTP_PASSORD = "client.auth.http.password"; +	public static final String PROP_CONFIG_CLIENT_AUTH_SSL_KEYSTORE_PATH = "client.auth.ssl.keystore.path"; +	public static final String PROP_CONFIG_CLIENT_AUTH_SSL_KEYSTORE_PASSORD = "client.auth.ssl.keystore.password"; +	public static final String PROP_CONFIG_CLIENT_AUTH_SSL_KEYSTORE_TYPE = "client.auth.ssl.keystore.type"; +	  	// default configuration values  	public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET = "15";  	public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_CONNECTION = "15"; @@ -46,6 +68,79 @@ public class HttpClientFactory implements IHttpClientFactory {  	public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXTOTAL = "500";  	public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXPERROUTE = "100"; +	public enum ClientAuthMode { +		NONE("none"), +		PASSWORD("password"), +		SSL("ssl"); +		 +		private final String mode; +		 +		private ClientAuthMode(String mode) { +			this.mode = mode; +		} +		 +		/** +		 * Get the PVP mode +		 *  +		 * @return +		 */ +		public String getMode() { +			return this.mode; +		} +		 +		public static ClientAuthMode fromString(String s) { +			try { +				return ClientAuthMode.valueOf(s.toUpperCase()); +				 +		    } catch (IllegalArgumentException|NullPointerException e) { +		    	return null; +		    } +		} +		 +		@Override +		public String toString() { +			return getMode(); +			 +		} +		 +	}; +	 +	public enum KeyStoreType { +		PKCS12("pkcs12"), +		JKS("jks"); +		 +		private final String type; +		 +		private KeyStoreType (String type) { +			this.type = type; +		} +		 +		/** +		 * Get the PVP mode +		 *  +		 * @return +		 */ +		public String getType() { +			return this.type; +		} +		 +		public static KeyStoreType fromString(String s) { +			try { +				return KeyStoreType.valueOf(s.toUpperCase()); +				 +		    } catch (IllegalArgumentException|NullPointerException e) { +		    	return null; +		    } +		} +		 +		@Override +		public String toString() { +			return getType(); +			 +		} +		 +	}; +	  	private HttpClientBuilder httpClientBuilder = null;  	/* (non-Javadoc) @@ -102,50 +197,155 @@ public class HttpClientFactory implements IHttpClientFactory {  											.build();		  		httpClientBuilder.setDefaultRequestConfig(requestConfig); -		//set  pool connection if requested -		if (basicConfig.getBasicConfigurationBoolean( -				PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_USE,  -				true)) { -			final PoolingHttpClientConnectionManager pool = new PoolingHttpClientConnectionManager(); -			pool.setDefaultMaxPerRoute(Integer.valueOf(basicConfig.getBasicConfiguration( -					PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXPERROUTE,  -					DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXPERROUTE)));			 -			pool.setMaxTotal(Integer.valueOf(basicConfig.getBasicConfiguration( -					PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXTOTAL,  -					DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXTOTAL))); +		//set  pool connection if required +		injectConnectionPoolIfRequired(); +		 +		final ClientAuthMode clientAuthMode = ClientAuthMode.fromString( +				basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_MODE, ClientAuthMode.NONE.getMode())); +		log.info("Client authentication-mode is set to: {}", clientAuthMode); +		 +		//inject basic http authentication if required +		injectBasicAuthenticationIfRequired(clientAuthMode); +				 +		//inject authentication if required +		injectSSLContext(clientAuthMode); +				 +	} + +	private void injectBasicAuthenticationIfRequired(ClientAuthMode clientAuthMode) { +		if (clientAuthMode.equals(ClientAuthMode.PASSWORD)) { +			final CredentialsProvider provider = new BasicCredentialsProvider(); +			final String username = basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_AUTH_HTTP_USERNAME); +			final String password = basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_AUTH_HTTP_PASSORD); +			if (StringUtils.isEmpty(username)) { +				log.warn("Http basic authentication was activated but NOT username was set!"); +				 +			} +			 +			log.trace("Injecting basic authentication with username: {} and password: {}", username, password);						 +			final UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password); +			provider.setCredentials(AuthScope.ANY, credentials); +			httpClientBuilder.setDefaultCredentialsProvider(provider);						 +			log.info("Basic http authentication was injected with username: {}", username); +			 +		} else { +			log.trace("Injection of Http Basic authentication was skipped"); -			httpClientBuilder.setConnectionManager(pool); -			log.debug("Initalize http-client pool with, maxTotal: {} maxPerRoute: {}", pool.getMaxTotal(), pool.getDefaultMaxPerRoute()); -					  		} +	} +	 +	private SSLContext buildSSLContextWithSSLClientAuthentication() throws KeyManagementException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException, EAAFConfigurationException  { +		log.trace("Injecting SSL client-authentication into http client ... ");				 +		final KeyStore keystore = getSSLAuthKeyStore(); +		final String keyPasswordString = basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_AUTH_SSL_KEYSTORE_PASSORD); +		log.trace("Open SSL Client-Auth keystore with password: {}", keyPasswordString); +		final char[] keyPassword = (keyPasswordString == null) ? StringUtils.EMPTY.toCharArray() : keyPasswordString.toCharArray(); +		return SSLContexts.custom().loadKeyMaterial(keystore, keyPassword).build(); +		 +	} +	 +	private KeyStore getSSLAuthKeyStore() throws EAAFConfigurationException { +		final KeyStoreType keyStoreType = KeyStoreType.fromString( +				basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_AUTH_SSL_KEYSTORE_TYPE, KeyStoreType.PKCS12.getType())); +		final String localKeyStorePath = basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_AUTH_SSL_KEYSTORE_PATH, StringUtils.EMPTY); +		final String keyStorePassword = basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_AUTH_SSL_KEYSTORE_PASSORD, StringUtils.EMPTY); +		 +		try {			 +			log.debug("Open keyStore with type: {}", keyStoreType);	 +			KeyStore clientStore; +			if (keyStoreType.equals(KeyStoreType.PKCS12)) { +				clientStore = KeyStore.getInstance("pkcs12");			 +			} else {  +				clientStore = KeyStore.getInstance("JKS");			 +			} +				 +		 +			log.debug("Read keyStore path: {} from configuration", localKeyStorePath);		 +			if (StringUtils.isNotEmpty(localKeyStorePath)) {			 +				String absFilePath = FileUtils.makeAbsoluteURL(localKeyStorePath, basicConfig.getConfigurationRootDirectory()); +				 +				if (absFilePath.startsWith("file:")) { +					absFilePath = absFilePath.substring("file:".length()); +					 +				} +				 +				final File keyStoreFile = new File(absFilePath); +				log.trace("Load keyStore: {} with password: {}", absFilePath, keyStorePassword); +				clientStore.load(new FileInputStream(keyStoreFile), keyStorePassword.toCharArray()); +			 +				return clientStore; +				 +			} else { +				log.warn("Path to keyStore for SSL Client-Authentication is empty or null"); +				throw new EAAFConfigurationException("Path to keyStore for SSL Client-Authentication is empty or null", new Object[] {}); +				 +			} +			 +		} catch (final KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) { +			log.warn("Can NOT read keyStore: {} from filesystem", localKeyStorePath, null,  e); +			throw new EAAFConfigurationException("Can NOT read keyStore: {} from filesystem", new Object[] {localKeyStorePath}, e); +			 +		} +				 +	} + +	private void injectSSLContext(ClientAuthMode clientAuthMode) {				 +		SSLContext sslContext = null;		  		try { -			log.trace("Initializing SSL Context ... "); -			final SSLContext sslContext = SSLContext.getDefault(); +			if (clientAuthMode.equals(ClientAuthMode.SSL)) { +				sslContext = buildSSLContextWithSSLClientAuthentication(); +										 +			} else { +				log.trace("Initializing default SSL Context ... "); +				sslContext = SSLContext.getDefault(); +			 +			} +		 +			//set hostname verifier  			HostnameVerifier hostnameVerifier = null;  			if (basicConfig.getBasicConfigurationBoolean(  					PROP_CONFIG_CLIENT_HTTP_SSL_HOSTNAMEVERIFIER_TRUSTALL,   					false)) {  				hostnameVerifier = new NoopHostnameVerifier();  				log.warn("HTTP client-builder deactivates SSL Host-name verification!"); +				  			} -			final LayeredConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext , hostnameVerifier); +			final LayeredConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext , hostnameVerifier);						  			httpClientBuilder.setSSLSocketFactory(sslSocketFactory ); -		} catch (final NoSuchAlgorithmException e) { +		} catch (final NoSuchAlgorithmException | KeyManagementException | UnrecoverableKeyException | KeyStoreException | EAAFConfigurationException e) {  			log.warn("HTTP client-builder can NOT initialze SSL-Context", e);  		} -  		log.info("HTTP client-builder successfuly initialized");  	} - +	private void injectConnectionPoolIfRequired() { +		if (basicConfig.getBasicConfigurationBoolean( +				PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_USE,  +				true)) { +			final PoolingHttpClientConnectionManager pool = new PoolingHttpClientConnectionManager(); +			pool.setDefaultMaxPerRoute(Integer.valueOf(basicConfig.getBasicConfiguration( +					PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXPERROUTE,  +					DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXPERROUTE)));			 +			pool.setMaxTotal(Integer.valueOf(basicConfig.getBasicConfiguration( +					PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXTOTAL,  +					DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXTOTAL))); +			 +			 +			 +			httpClientBuilder.setConnectionManager(pool); +			log.debug("Initalize http-client pool with, maxTotal: {} maxPerRoute: {}", pool.getMaxTotal(), pool.getDefaultMaxPerRoute()); +					 +		} +		 +	} | 
