From 759ac5f42c6aff901dbeede4fbf1a1d2e08cad0f Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Wed, 4 Dec 2019 19:43:32 +0100 Subject: common EGIZ code-style refactoring --- eaaf_core_utils/pom.xml | 211 +++--- .../idp/process/support/SecureRandomHolder.java | 92 ++- .../core/impl/logging/SimpleStatusMessager.java | 62 +- .../gv/egiz/eaaf/core/impl/utils/ArrayUtils.java | 62 +- .../egiz/eaaf/core/impl/utils/DataURLBuilder.java | 113 ---- .../egiz/eaaf/core/impl/utils/DataUrlBuilder.java | 91 +++ .../at/gv/egiz/eaaf/core/impl/utils/FileUtils.java | 257 ++++---- .../at/gv/egiz/eaaf/core/impl/utils/HTTPUtils.java | 178 ------ .../eaaf/core/impl/utils/HttpClientFactory.java | 711 +++++++++++---------- .../at/gv/egiz/eaaf/core/impl/utils/HttpUtils.java | 119 ++++ .../eaaf/core/impl/utils/IHttpClientFactory.java | 29 +- .../egiz/eaaf/core/impl/utils/KeyStoreUtils.java | 248 ++++--- .../egiz/eaaf/core/impl/utils/KeyValueUtils.java | 697 ++++++++++---------- .../eaaf/core/impl/utils/NodeIteratorAdapter.java | 88 ++- .../egiz/eaaf/core/impl/utils/NodeListAdapter.java | 64 +- .../at/gv/egiz/eaaf/core/impl/utils/Random.java | 290 +++++---- .../SecurePendingRequestIdGenerationStrategy.java | 390 +++++------ .../gv/egiz/eaaf/core/impl/utils/ServletUtils.java | 64 +- .../SimplePendingRequestIdGenerationStrategy.java | 58 +- .../gv/egiz/eaaf/core/impl/utils/StreamUtils.java | 177 +++-- .../eaaf/core/impl/utils/TransactionIDUtils.java | 101 --- .../eaaf/core/impl/utils/TransactionIdUtils.java | 94 +++ .../at/gv/egiz/eaaf/core/impl/utils/X509Utils.java | 87 ++- .../impl/logging/JUnitTestStatusMessenger.java | 97 +-- .../core/impl/utils/test/KeyValueUtilsTest.java | 446 +++++++++++++ 25 files changed, 2620 insertions(+), 2206 deletions(-) delete mode 100644 eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DataURLBuilder.java create mode 100644 eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DataUrlBuilder.java delete mode 100644 eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HTTPUtils.java create mode 100644 eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HttpUtils.java delete mode 100644 eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIDUtils.java create mode 100644 eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIdUtils.java create mode 100644 eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/KeyValueUtilsTest.java (limited to 'eaaf_core_utils') diff --git a/eaaf_core_utils/pom.xml b/eaaf_core_utils/pom.xml index adf8afa8..84ab46f5 100644 --- a/eaaf_core_utils/pom.xml +++ b/eaaf_core_utils/pom.xml @@ -1,17 +1,19 @@ - + 4.0.0 at.gv.egiz eaaf - 1.1.0-SNAPSHOT + 1.1.0-SNAPSHOT at.gv.egiz.eaaf eaaf_core_utils Utils for EAAF core components Core component Utils for identity managment implementations - + European Union Public License, version 1.2 (EUPL-1.2) @@ -28,74 +30,79 @@ https://www.egiz.gv.at - + UTF-8 - - - - at.gv.egiz.eaaf - eaaf_core_api - - - org.springframework - spring-webmvc - - - - org.slf4j - slf4j-api - - - org.apache.commons - commons-lang3 - - - org.apache.httpcomponents - httpclient - - - org.apache.httpcomponents - httpcore - - - com.google.code.findbugs - jsr305 - - - joda-time - joda-time - - - javax.servlet - javax.servlet-api - provided - - - - junit - junit - test - - - org.springframework - spring-test - test - - + + + at.gv.egiz.eaaf + eaaf_core_api + + + + org.springframework + spring-webmvc + + + + org.slf4j + slf4j-api + + + org.apache.commons + commons-lang3 + + + org.apache.httpcomponents + httpclient + + + org.apache.httpcomponents + httpcore + + + com.google.code.findbugs + jsr305 + + + joda-time + joda-time + + + javax.servlet + javax.servlet-api + provided + + + + junit + junit + test + + + org.springframework + spring-test + test + + + com.google.guava + guava + test + + - - - eaaf_core_utils - - - - src/main/resources - - - + + + eaaf_core_utils + + + + src/main/resources + + + org.apache.maven.plugins @@ -106,45 +113,45 @@ 1.8 - - - compile - testCompile - - + + + compile + testCompile + + - org.apache.maven.plugins - maven-jar-plugin - 3.1.0 - - - - test-jar - - - - - + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + + test-jar + + + + + - - maven-surefire-plugin - ${surefire.version} - - 1 - - - - org.apache.maven.surefire - surefire-junit47 - ${surefire.version} - - - - + + maven-surefire-plugin + ${surefire.version} + + 1 + + + + org.apache.maven.surefire + surefire-junit47 + ${surefire.version} + + + + - - + + diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/support/SecureRandomHolder.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/support/SecureRandomHolder.java index a297367f..8584d63f 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/support/SecureRandomHolder.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/support/SecureRandomHolder.java @@ -1,61 +1,57 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.idp.process.support; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; /** - * Holder for a secure random instance following the initialization on demand holder design pattern. The secure random - * instance is a singleton that is initialized on first usage. - * + * Holder for a secure random instance following the initialization on demand holder design pattern. + * The secure random instance is a singleton that is initialized on first usage. + * * @author tknall - * + * */ public class SecureRandomHolder { - private SecureRandomHolder() { - } - - private static final SecureRandom SRND_INSTANCE; - static { - try { - SRND_INSTANCE = SecureRandom.getInstance("SHA1PRNG"); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("Unable to instantiate SHA1PRNG.", e); - } - } - - /** - * Returns a secure random generator instance. - * @return The secure random instance. - */ - public static SecureRandom getInstance() { - return SecureRandomHolder.SRND_INSTANCE; - } - -} \ No newline at end of file + private SecureRandomHolder() { + + } + + private static final SecureRandom SRND_INSTANCE; + + static { + try { + SRND_INSTANCE = SecureRandom.getInstance("SHA1PRNG"); + } catch (final NoSuchAlgorithmException e) { + throw new RuntimeException("Unable to instantiate SHA1PRNG.", e); + } + } + + /** + * Returns a secure random generator instance. + * + * @return The secure random instance. + */ + public static SecureRandom getInstance() { + return SecureRandomHolder.SRND_INSTANCE; + } + +} 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 index d36c79b9..5715a7b6 100644 --- 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 @@ -1,44 +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} - * + * 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; - } + private static final String NOTSUPPORTED = "Error response-codes not supported"; + private static final String NULLMESSAGE = "No error-message provided"; + + @Override + public String getMessage(final String messageId, final Object[] parameters) { + return getMessageWithoutDefault(messageId, parameters); + + } + + @Override + public String getMessageWithoutDefault(final String messageId, final Object[] parameters) { + if (messageId != null) { + return MessageFormat.format(messageId, parameters); + + } + + return NULLMESSAGE; + } + + @Override + public String getResponseErrorCode(final Throwable throwable) { + return NOTSUPPORTED; + } + + @Override + public String mapInternalErrorToExternalError(final String intErrorCode) { + return NOTSUPPORTED; + } } diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/ArrayUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/ArrayUtils.java index 8585bc05..1da82f43 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/ArrayUtils.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/ArrayUtils.java @@ -1,44 +1,42 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. + */ + package at.gv.egiz.eaaf.core.impl.utils; import java.util.List; public class ArrayUtils { - /** - * Check if a String 's' is part of a List 'l' in qualsIgnoreCase mode - * - * @param s Search String - * @param l List of String elements - * @return true if 's' is in 'l', otherwise false - */ - public static boolean containsCaseInsensitive(String s, List l){ - if (l == null || s == null) - return false; - - return l.stream().anyMatch(x -> x.equalsIgnoreCase(s)); - + /** + * Check if a String 's' is part of a List 'l' in qualsIgnoreCase mode. + * + * @param s Search String + * @param l List of String elements + * @return true if 's' is in 'l', otherwise false + */ + public static boolean containsCaseInsensitive(final String s, final List l) { + if (l == null || s == null) { + return false; } + return l.stream().anyMatch(x -> x.equalsIgnoreCase(s)); + + } + } diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DataURLBuilder.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DataURLBuilder.java deleted file mode 100644 index a81fafbc..00000000 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DataURLBuilder.java +++ /dev/null @@ -1,113 +0,0 @@ -/******************************************************************************* - * Copyright 2014 Federal Chancellery Austria - * MOA-ID has been developed in a cooperation between BRZ, the Federal - * Chancellery Austria - ICT staff unit, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://www.osor.eu/eupl/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - ******************************************************************************/ -/* - * Copyright 2003 Federal Chancellery Austria - * MOA-ID has been developed in a cooperation between BRZ, the Federal - * Chancellery Austria - ICT staff unit, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://www.osor.eu/eupl/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - */ - - -package at.gv.egiz.eaaf.core.impl.utils; - -import org.apache.commons.lang3.StringUtils; - -import at.gv.egiz.eaaf.core.api.data.EAAFConstants; - -/** - * Builds a DataURL parameter meant for the security layer implementation - * to respond to. - * - * @author Paul Ivancsics - * @version $Id$ - */ -public class DataURLBuilder { - - /** - * Constructor for DataURLBuilder. - */ - public DataURLBuilder() { - super(); - } - - /** - * Constructs a data URL for VerifyIdentityLink or VerifyAuthenticationBlock, - * including the MOASessionID as a parameter. - * - * @param authBaseURL base URL (context path) of the MOA ID Authentication component, - * including a trailing '/' - * @param authServletName request part of the data URL - * @param pendingReqId sessionID to be included in the dataURL - * @return String - */ - public String buildDataURL(String authBaseURL, String authServletName, String pendingReqId) { - String dataURL; - if (!authBaseURL.endsWith("/")) - authBaseURL += "/"; - - if (authServletName.startsWith("/")) - authServletName = authServletName.substring(1); - - dataURL = authBaseURL + authServletName; - - if (StringUtils.isNotEmpty(pendingReqId)) - dataURL = addParameter(dataURL, EAAFConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID, pendingReqId); - - return dataURL; - } - - /** - * Method addParameter. - * @param urlString represents the url - * @param paramname is the parameter to be added - * @param value is the value of that parameter - * @return String - */ - private String addParameter(String urlString, String paramname, String value) { - String url = urlString; - if (paramname != null) { - if (url.indexOf("?") < 0) - url += "?"; - else - url += "&"; - url += paramname + "=" + value; - } - return url; - } -} diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DataUrlBuilder.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DataUrlBuilder.java new file mode 100644 index 00000000..a72e07dd --- /dev/null +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DataUrlBuilder.java @@ -0,0 +1,91 @@ +/* + * Copyright 2014 Federal Chancellery Austria MOA-ID has been developed in a cooperation between + * BRZ, the Federal Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.gv.egiz.eaaf.core.impl.utils; + +import org.apache.commons.lang3.StringUtils; + +import at.gv.egiz.eaaf.core.api.data.EAAFConstants; + +/** + * Builds a DataURL parameter meant for the security layer implementation to respond to. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class DataUrlBuilder { + + /** + * Constructor for DataURLBuilder. + */ + public DataUrlBuilder() { + super(); + } + + /** + * Constructs a data URL for VerifyIdentityLink or + * VerifyAuthenticationBlock, including the MOASessionID as a parameter. + * + * @param authBaseUrl base URL (context path) of the MOA ID Authentication component, including a + * trailing '/' + * @param authServletName request part of the data URL + * @param pendingReqId sessionID to be included in the dataURL + * @return String + */ + public String buildDataUrl(String authBaseUrl, String authServletName, + final String pendingReqId) { + String dataUrl; + if (!authBaseUrl.endsWith("/")) { + authBaseUrl += "/"; + } + + if (authServletName.startsWith("/")) { + authServletName = authServletName.substring(1); + } + + dataUrl = authBaseUrl + authServletName; + + if (StringUtils.isNotEmpty(pendingReqId)) { + dataUrl = + addParameter(dataUrl, EAAFConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID, pendingReqId); + } + + return dataUrl; + } + + /** + * Method addParameter. + * + * @param urlString represents the url + * @param paramname is the parameter to be added + * @param value is the value of that parameter + * @return String + */ + private String addParameter(final String urlString, final String paramname, final String value) { + String url = urlString; + if (paramname != null) { + if (url.indexOf("?") < 0) { + url += "?"; + } else { + url += "&"; + } + url += paramname + "=" + value; + } + return url; + } +} diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/FileUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/FileUtils.java index 6ac51ac4..943d3dad 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/FileUtils.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/FileUtils.java @@ -1,29 +1,22 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. + */ + package at.gv.egiz.eaaf.core.impl.utils; @@ -38,22 +31,22 @@ import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; - import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FileUtils { - private static final Logger log = LoggerFactory.getLogger(FileUtils.class); - - + private static final Logger log = LoggerFactory.getLogger(FileUtils.class); + + /** * Reads a file, given by URL, into a byte array. + * * @param urlString file URL * @return file content * @throws IOException on any exception thrown */ - public static byte[] readURL(String urlString) throws IOException { + public static byte[] readUrl(final String urlString) throws IOException { final URL url = new URL(urlString); final InputStream in = new BufferedInputStream(url.openStream()); final byte[] content = StreamUtils.readStream(in); @@ -63,114 +56,142 @@ public class FileUtils { /** * Reads a file from a resource. + * * @param name resource name * @return file content as a byte array * @throws IOException on any exception thrown */ - public static byte[] readResource(String name) throws IOException { + public static byte[] readResource(final String name) throws IOException { final ClassLoader cl = FileUtils.class.getClassLoader(); final BufferedInputStream in = new BufferedInputStream(cl.getResourceAsStream(name)); final byte[] content = StreamUtils.readStream(in); in.close(); return content; } + /** * Reads a file from a resource. + * * @param name filename * @param encoding character encoding * @return file content * @throws IOException on any exception thrown */ - public static String readResource(String name, String encoding) throws IOException { + public static String readResource(final String name, final String encoding) throws IOException { final byte[] content = readResource(name); return new String(content, encoding); } - - - /** - * Returns the absolute URL of a given url which is relative to the parameter root - * @param url - * @param root - * @return String - * @throws MalformedURLException - */ - public static String makeAbsoluteURL(String url, URI root) throws MalformedURLException { - if (root != null) - return makeAbsoluteURL(url, root.toURL().toString()); - else - return makeAbsoluteURL(url, StringUtils.EMPTY); - - } - - /** - * Returns the absolute URL of a given url which is relative to the parameter root - * @param url - * @param root - * @return String - */ - public static String makeAbsoluteURL(String url, String root) { - //if url is relative to rootConfigFileDirName make it absolute - - log.trace("Making AbsoluteURL URL: " + url + " Root-Path: " + root); - - if (StringUtils.isEmpty(root)) - root = null; - - File keyFile; - String newURL = url; - - if(null == url) return null; - - if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("file:") - || url.startsWith("ftp:") || url.startsWith("classpath:")) { - return url; - - } else { - // check if absolute - if not make it absolute - keyFile = new File(url); - if (!keyFile.isAbsolute()) { - keyFile = new File(root, url); - - if (keyFile.toString().startsWith("file:")) - newURL = keyFile.toString(); - - else - newURL = keyFile.toURI().toString(); - - } - return newURL; - } - } - - - private static void copy( InputStream fis, OutputStream fos ) - { - try - { - final byte[] buffer = new byte[ 0xFFFF ]; - for ( int len; (len = fis.read(buffer)) != -1; ) - fos.write( buffer, 0, len ); - } - catch( final IOException e ) { - System.err.println( e ); - } - finally { - if ( fis != null ) - try { fis.close(); } catch ( final IOException e ) { e.printStackTrace(); } - if ( fos != null ) - try { fos.close(); } catch ( final IOException e ) { e.printStackTrace(); } - } - } - - public static void copyFile(File src, File dest) - { - try - { - copy( new FileInputStream( src ), new FileOutputStream( dest ) ); - } - catch( final IOException e ) { - e.printStackTrace(); - } - } - + + + /** + * Returns the absolute URL of a given url which is relative to the parameter root. + * + * @param url Filepath + * @param root configuration root context + * @return absolut filepath + * @throws MalformedURLException In case of a filepath error + */ + public static String makeAbsoluteUrl(final String url, final URI root) + throws MalformedURLException { + if (root != null) { + return makeAbsoluteUrl(url, root.toURL().toString()); + } else { + return makeAbsoluteUrl(url, StringUtils.EMPTY); + } + + } + + /** + * Returns the absolute URL of a given url which is relative to the parameter root. + * + * @param url Filepath + * @param root configuration root context + * @return absolut filepath + */ + public static String makeAbsoluteUrl(final String url, String root) { + // if url is relative to rootConfigFileDirName make it absolute + + log.trace("Making AbsoluteURL URL: " + url + " Root-Path: " + root); + + if (StringUtils.isEmpty(root)) { + root = null; + } + + File keyFile; + String newUrl = url; + + if (null == url) { + return null; + } + + if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("file:") + || url.startsWith("ftp:") || url.startsWith("classpath:")) { + return url; + + } else { + // check if absolute - if not make it absolute + keyFile = new File(url); + if (!keyFile.isAbsolute()) { + keyFile = new File(root, url); + + if (keyFile.toString().startsWith("file:")) { + newUrl = keyFile.toString(); + } else { + newUrl = keyFile.toURI().toString(); + } + + } + return newUrl; + } + } + + + private static void copy(final InputStream fis, final OutputStream fos) { + try { + final byte[] buffer = new byte[0xFFFF]; + for (int len; (len = fis.read(buffer)) != -1;) { + fos.write(buffer, 0, len); + } + } catch (final IOException e) { + System.err.println(e); + + } + } + + /** + * Copy file from source to destination. + * + * @param src File source + * @param dest file destination + */ + public static void copyFile(final File src, final File dest) { + InputStream fis = null; + OutputStream fos = null; + + try { + fis = new FileInputStream(src); + fos = new FileOutputStream(src); + copy(fis, fos); + + } catch (final IOException e) { + e.printStackTrace(); + + } finally { + if (fis != null) { + try { + fis.close(); + } catch (final IOException e) { + e.printStackTrace(); + } + } + if (fos != null) { + try { + fos.close(); + } catch (final IOException e) { + e.printStackTrace(); + } + } + } + } + } diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HTTPUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HTTPUtils.java deleted file mode 100644 index cf1abaa7..00000000 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HTTPUtils.java +++ /dev/null @@ -1,178 +0,0 @@ -/******************************************************************************* - * Copyright 2014 Federal Chancellery Austria - * MOA-ID has been developed in a cooperation between BRZ, the Federal - * Chancellery Austria - ICT staff unit, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://www.osor.eu/eupl/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - ******************************************************************************/ -/* - * Copyright 2003 Federal Chancellery Austria - * MOA-ID has been developed in a cooperation between BRZ, the Federal - * Chancellery Austria - ICT staff unit, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://www.osor.eu/eupl/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - */ - - -package at.gv.egiz.eaaf.core.impl.utils; - -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.lang3.StringUtils; - - -/** - * - * @author Rudolf Schamberger - * - */ -public class HTTPUtils { - -// /** -// * Utility used to obtainin correct encoded HTTP content. -// * Reads a given Content adressed by HTTP-URL into String. -// * Content encoding is considered by using the Content-Type HTTP header charset value. -// * @param URL HTTP URL to read from. -// * @return String representation of content -// * @throws IOException on data-reading problems -// */ -// public static String readHttpURL(String URL) -// throws IOException { -// -// URL url = new URL(URL); -// HttpURLConnection conn = (HttpURLConnection)url.openConnection(); -// conn.setRequestMethod("GET"); -// String contentType = conn.getContentType(); -// RE regExp = null; -// try { -// regExp = new RE("(;.*charset=)(\"*)(.*[^\"])"); -// } catch (RESyntaxException e) { -// //RESyntaxException is not possible = expr. is costant -// } -// boolean charsetSupplied = regExp.match(contentType); -// String encoding = "ISO-8859-1"; //default HTTP encoding -// if (charsetSupplied) { -// encoding = regExp.getParen(3); -// } -// InputStream instream = new BufferedInputStream(conn.getInputStream()); -// InputStreamReader isr = new InputStreamReader(instream, encoding); -// Reader in = new BufferedReader(isr); -// int ch; -// StringBuffer buffer = new StringBuffer(); -// while ((ch = in.read()) > -1) { -// buffer.append((char)ch); -// } -// in.close(); -// conn.disconnect(); -// return buffer.toString(); -// } - - /** - * Helper method to retrieve server URL including context path - * @param request HttpServletRequest - * @return Server URL including context path (e.g. http://localhost:8443/moa-id-auth - */ - public static String getBaseURL(HttpServletRequest request) { - StringBuffer buffer = new StringBuffer(getServerURL(request)); - - // add context path if available - String contextPath = request.getContextPath(); - if (!StringUtils.isEmpty(contextPath)) { - buffer.append(contextPath); - } - - return buffer.toString(); - } - - /** - * Helper method to retrieve server URL - * @param request HttpServletRequest - * @return Server URL (e.g. http://localhost:8443) - */ - public static String getServerURL(HttpServletRequest request) { - StringBuffer buffer = new StringBuffer(); - - // get protocol - String protocol = request.getScheme(); - buffer.append(protocol).append("://"); - - // server name - buffer.append(request.getServerName()); - - // add port if necessary - int port = request.getServerPort(); - if ((protocol.equals("http") && port != 80) || (protocol.equals("https") && port != 443)) { - buffer.append(':'); - buffer.append(port); - } - - return buffer.toString(); - } - - /** - * Extract the IDP PublicURLPrefix from authrequest - * - * @param req HttpServletRequest - * @return PublicURLPrefix which ends always without / - */ - public static String extractAuthURLFromRequest(HttpServletRequest req) { - String authURL = req.getScheme() + "://" + req.getServerName(); - if ((req.getScheme().equalsIgnoreCase("https") && req.getServerPort()!=443) || (req.getScheme().equalsIgnoreCase("http") && req.getServerPort()!=80)) { - authURL = authURL.concat(":" + req.getServerPort()); - } - authURL = authURL.concat(req.getContextPath()); - return authURL; - - } - - /** - * Extract the IDP requested URL from authrequest - * - * @param req HttpServletRequest - * @return RequestURL which ends always without / - */ - public static String extractAuthServletPathFromRequest(HttpServletRequest req) { - return extractAuthURLFromRequest(req).concat(req.getServletPath()); - - } - - public static String addURLParameter(String url, String paramname, - String paramvalue) { - String param = paramname + "=" + paramvalue; - if (url.indexOf("?") < 0) - return url + "?" + param; - else - return url + "&" + param; - } - -} 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 a8cfa7c1..4e8be52e 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 @@ -8,11 +8,11 @@ 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 at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; @@ -44,339 +44,378 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; -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); - @Autowired(required=true) private IConfiguration basicConfig; - @Autowired(required=true) ResourceLoader resourceLoader; - - public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_USE = "client.http.connection.pool.use"; - public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXTOTAL = "client.http.connection.pool.maxtotal"; - public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXPERROUTE = "client.http.connection.pool.maxperroute"; - public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET = "client.http.connection.timeout.socket"; - public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_CONNECTION = "client.http.connection.timeout.connection"; - 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"; - public static final String PROP_CONFIG_CLIENT_AUTH_SSL_KEY_PASSWORD = "client.auth.ssl.key.password"; - public static final String PROP_CONFIG_CLIENT_AUTH_SSL_KEY_ALIAS = "client.auth.ssl.key.alias"; - - // 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"; - public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_REQUEST = "30"; - 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) - * @see at.gv.egiz.eaaf.core.impl.utils.IHttpClientFactory#getHttpClient() - */ - @Override - public CloseableHttpClient getHttpClient() { - return getHttpClient(true); - - } - - @Override - public CloseableHttpClient getHttpClient(boolean followRedirects) { - RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); - if (!followRedirects) - redirectStrategy = new RedirectStrategy() { - - @Override - public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) - throws ProtocolException { - return false; - } - - @Override - public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) - throws ProtocolException { - return null; - } - }; - - return httpClientBuilder - .setRedirectStrategy(redirectStrategy) - .build(); - - } - - @PostConstruct - private void initalize() { - //initialize http client - log.trace("Initializing HTTP Client-builder ... "); - httpClientBuilder = HttpClients.custom(); - - //set default request configuration - final RequestConfig requestConfig = RequestConfig.custom() - .setConnectTimeout(Integer.valueOf(basicConfig.getBasicConfiguration( - PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_CONNECTION, - DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_CONNECTION)) * 1000) - .setConnectionRequestTimeout(Integer.valueOf(basicConfig.getBasicConfiguration( - PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_REQUEST, - DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_REQUEST)) * 1000) - .setSocketTimeout(Integer.valueOf(basicConfig.getBasicConfiguration( - PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET, - DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET)) * 1000) - .build(); - httpClientBuilder.setDefaultRequestConfig(requestConfig); - - ClientAuthMode clientAuthMode = ClientAuthMode.fromString( - basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_MODE, ClientAuthMode.NONE.getMode())); - if (clientAuthMode == null) { - log.warn("Can Not parse ClientAuthMode! Set mode to default value"); - clientAuthMode = ClientAuthMode.NONE; - - } - - //inject basic http authentication if required - log.info("Client authentication-mode is set to: {}", clientAuthMode); - injectBasicAuthenticationIfRequired(clientAuthMode); - - //inject authentication if required - final LayeredConnectionSocketFactory sslConnectionFactory = getSSLContext(clientAuthMode); - - //set pool connection if required - injectConnectionPoolIfRequired(sslConnectionFactory); - - - } - - 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"); - - } - - } - - 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_KEY_PASSWORD); - 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)) { - final String absFilePath = FileUtils.makeAbsoluteURL(localKeyStorePath, basicConfig.getConfigurationRootDirectory()); - final Resource ressource = resourceLoader.getResource(absFilePath); - final InputStream is = ressource.getInputStream(); - log.trace("Load keyStore: {} with password: {}", absFilePath, keyStorePassword); - clientStore.load(is, keyStorePassword.toCharArray()); - is.close(); - - 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 LayeredConnectionSocketFactory getSSLContext(ClientAuthMode clientAuthMode) { - SSLContext sslContext = null; - try { - 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); - - return sslSocketFactory; - - } 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"); - return null; - - } - - private void injectConnectionPoolIfRequired(LayeredConnectionSocketFactory sslConnectionFactory) { - if (basicConfig.getBasicConfigurationBoolean( - PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_USE, - true)) { - PoolingHttpClientConnectionManager pool; - - //set socketFactoryRegistry if SSLConnectionFactory is Set - if (sslConnectionFactory != null) { - final Registry socketFactoryRegistry = RegistryBuilder.create() - .register("http", PlainConnectionSocketFactory.getSocketFactory()) - .register("https", sslConnectionFactory) - .build(); - log.trace("Inject SSLSocketFactory into pooled connection"); - pool = new PoolingHttpClientConnectionManager(socketFactoryRegistry); - - } else { - 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()); - - } else if (sslConnectionFactory != null) { - log.trace("Inject SSLSocketFactory without connection pool"); - httpClientBuilder.setSSLSocketFactory(sslConnectionFactory ); - - } - - - } - - - + private static final Logger log = LoggerFactory.getLogger(HttpClientFactory.class); + @Autowired(required = true) + private IConfiguration basicConfig; + @Autowired(required = true) + ResourceLoader resourceLoader; + + public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_USE = + "client.http.connection.pool.use"; + public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXTOTAL = + "client.http.connection.pool.maxtotal"; + public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXPERROUTE = + "client.http.connection.pool.maxperroute"; + public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET = + "client.http.connection.timeout.socket"; + public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_CONNECTION = + "client.http.connection.timeout.connection"; + 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"; + public static final String PROP_CONFIG_CLIENT_AUTH_SSL_KEY_PASSWORD = + "client.auth.ssl.key.password"; + public static final String PROP_CONFIG_CLIENT_AUTH_SSL_KEY_ALIAS = "client.auth.ssl.key.alias"; + + // 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"; + public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_REQUEST = "30"; + 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(final String mode) { + this.mode = mode; + } + + /** + * Get the PVP mode. + * + * @return + */ + public String getMode() { + return this.mode; + } + + /** + * Get http-client authentication mode from String representation. + * + * @param s Config parameter + * @return + */ + public static ClientAuthMode fromString(final 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(final String type) { + this.type = type; + } + + /** + * Get the KeyStore type. + * + * @return + */ + public String getType() { + return this.type; + } + + /** + * Get Keystore type from configuration. + * + * @param s String representation for keyStore type + * @return + */ + public static KeyStoreType fromString(final 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) + * + * @see at.gv.egiz.eaaf.core.impl.utils.IHttpClientFactory#getHttpClient() + */ + @Override + public CloseableHttpClient getHttpClient() { + return getHttpClient(true); + + } + + @Override + public CloseableHttpClient getHttpClient(final boolean followRedirects) { + RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); + if (!followRedirects) { + redirectStrategy = new RedirectStrategy() { + + @Override + public boolean isRedirected(final HttpRequest request, final HttpResponse response, + final HttpContext context) throws ProtocolException { + return false; + } + + @Override + public HttpUriRequest getRedirect(final HttpRequest request, final HttpResponse response, + final HttpContext context) throws ProtocolException { + return null; + } + }; + } + + return httpClientBuilder.setRedirectStrategy(redirectStrategy).build(); + + } + + @PostConstruct + private void initalize() { + // initialize http client + log.trace("Initializing HTTP Client-builder ... "); + httpClientBuilder = HttpClients.custom(); + + // set default request configuration + final RequestConfig requestConfig = + RequestConfig.custom() + .setConnectTimeout( + Integer.parseInt(basicConfig.getBasicConfiguration( + PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_CONNECTION, + DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_CONNECTION)) * 1000) + .setConnectionRequestTimeout(Integer.parseInt(basicConfig.getBasicConfiguration( + PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_REQUEST, + DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_REQUEST)) * 1000) + .setSocketTimeout(Integer.parseInt( + basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET, + DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET)) + * 1000) + .build(); + httpClientBuilder.setDefaultRequestConfig(requestConfig); + + ClientAuthMode clientAuthMode = ClientAuthMode.fromString( + basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_MODE, ClientAuthMode.NONE.getMode())); + if (clientAuthMode == null) { + log.warn("Can Not parse ClientAuthMode! Set mode to default value"); + clientAuthMode = ClientAuthMode.NONE; + + } + + // inject basic http authentication if required + log.info("Client authentication-mode is set to: {}", clientAuthMode); + injectBasicAuthenticationIfRequired(clientAuthMode); + + // inject authentication if required + final LayeredConnectionSocketFactory sslConnectionFactory = getSslContext(clientAuthMode); + + // set pool connection if required + injectConnectionPoolIfRequired(sslConnectionFactory); + + + } + + private void injectBasicAuthenticationIfRequired(final 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"); + + } + + } + + 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_KEY_PASSWORD); + 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)) { + final String absFilePath = FileUtils.makeAbsoluteUrl(localKeyStorePath, + basicConfig.getConfigurationRootDirectory()); + final Resource ressource = resourceLoader.getResource(absFilePath); + final InputStream is = ressource.getInputStream(); + log.trace("Load keyStore: {} with password: {}", absFilePath, keyStorePassword); + clientStore.load(is, keyStorePassword.toCharArray()); + is.close(); + + 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 LayeredConnectionSocketFactory getSslContext(final ClientAuthMode clientAuthMode) { + SSLContext sslContext = null; + try { + 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); + + return sslSocketFactory; + + } 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"); + return null; + + } + + private void injectConnectionPoolIfRequired( + final LayeredConnectionSocketFactory sslConnectionFactory) { + if (basicConfig.getBasicConfigurationBoolean(PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_USE, + true)) { + PoolingHttpClientConnectionManager pool; + + // set socketFactoryRegistry if SSLConnectionFactory is Set + if (sslConnectionFactory != null) { + final Registry socketFactoryRegistry = + RegistryBuilder.create() + .register("http", PlainConnectionSocketFactory.getSocketFactory()) + .register("https", sslConnectionFactory).build(); + log.trace("Inject SSLSocketFactory into pooled connection"); + pool = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + + } else { + pool = new PoolingHttpClientConnectionManager(); + + } + + pool.setDefaultMaxPerRoute(Integer.parseInt( + basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXPERROUTE, + DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXPERROUTE))); + pool.setMaxTotal(Integer.parseInt( + 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()); + + } else if (sslConnectionFactory != null) { + log.trace("Inject SSLSocketFactory without connection pool"); + httpClientBuilder.setSSLSocketFactory(sslConnectionFactory); + + } + + + } + + + } diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HttpUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HttpUtils.java new file mode 100644 index 00000000..394d2843 --- /dev/null +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HttpUtils.java @@ -0,0 +1,119 @@ +/* + * Copyright 2014 Federal Chancellery Austria MOA-ID has been developed in a cooperation between + * BRZ, the Federal Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.gv.egiz.eaaf.core.impl.utils; + +import javax.servlet.http.HttpServletRequest; +import org.apache.commons.lang3.StringUtils; + + + +public class HttpUtils { + + + /** + * Helper method to retrieve server URL including context path. + * + * @param request HttpServletRequest + * @return Server URL including context path (e.g. http://localhost:8443/moa-id-auth + */ + public static String getBaseUrl(final HttpServletRequest request) { + final StringBuffer buffer = new StringBuffer(getServerUrl(request)); + + // add context path if available + final String contextPath = request.getContextPath(); + if (!StringUtils.isEmpty(contextPath)) { + buffer.append(contextPath); + } + + return buffer.toString(); + } + + /** + * Helper method to retrieve server URL. + * + * @param request HttpServletRequest + * @return Server URL (e.g. http://localhost:8443) + */ + public static String getServerUrl(final HttpServletRequest request) { + final StringBuffer buffer = new StringBuffer(); + + // get protocol + final String protocol = request.getScheme(); + buffer.append(protocol).append("://"); + + // server name + buffer.append(request.getServerName()); + + // add port if necessary + final int port = request.getServerPort(); + if ((protocol.equals("http") && port != 80) || (protocol.equals("https") && port != 443)) { + buffer.append(':'); + buffer.append(port); + } + + return buffer.toString(); + } + + /** + * Extract the IDP PublicURLPrefix from authrequest. + * + * @param req HttpServletRequest + * @return PublicURLPrefix which ends always without / + */ + public static String extractAuthUrlFromRequest(final HttpServletRequest req) { + String authUrl = req.getScheme() + "://" + req.getServerName(); + if ((req.getScheme().equalsIgnoreCase("https") && req.getServerPort() != 443) + || (req.getScheme().equalsIgnoreCase("http") && req.getServerPort() != 80)) { + authUrl = authUrl.concat(":" + req.getServerPort()); + } + authUrl = authUrl.concat(req.getContextPath()); + return authUrl; + + } + + /** + * Extract the IDP requested URL from authrequest. + * + * @param req HttpServletRequest + * @return RequestURL which ends always without / + */ + public static String extractAuthServletPathFromRequest(final HttpServletRequest req) { + return extractAuthUrlFromRequest(req).concat(req.getServletPath()); + + } + + /** + * Add a http GET parameter to URL. + * + * @param url URL + * @param paramname Name of the parameter. + * @param paramvalue Value of the parameter. + * @return + */ + public static String addUrlParameter(final String url, final String paramname, + final String paramvalue) { + final String param = paramname + "=" + paramvalue; + if (url.indexOf("?") < 0) { + return url + "?" + param; + } else { + return url + "&" + param; + } + } + +} diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/IHttpClientFactory.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/IHttpClientFactory.java index 1975fb52..0dc00573 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/IHttpClientFactory.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/IHttpClientFactory.java @@ -4,18 +4,19 @@ import org.apache.http.impl.client.CloseableHttpClient; public interface IHttpClientFactory { - /** - * Return an instance of a Apache HTTP client that follows http redirects automatically - * - * @return - */ - CloseableHttpClient getHttpClient(); + /** + * Return an instance of a Apache HTTP client that follows http redirects automatically. + * + * @return + */ + CloseableHttpClient getHttpClient(); - /** - * Return an instance of a Apache HTTP client - * @param followRedirects - * @return - */ - CloseableHttpClient getHttpClient(boolean followRedirects); - -} \ No newline at end of file + /** + * Return an instance of a Apache HTTP client. + * + * @param followRedirects if false, the client does not flow 30x http redirects + * @return + */ + CloseableHttpClient getHttpClient(boolean followRedirects); + +} diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyStoreUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyStoreUtils.java index e3d74066..18ddf422 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyStoreUtils.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyStoreUtils.java @@ -1,36 +1,28 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. + */ + package at.gv.egiz.eaaf.core.impl.utils; import java.io.BufferedInputStream; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.URL; @@ -42,27 +34,27 @@ import java.security.cert.CertificateFactory; /** * Utility for creating and loading key stores. - * + * * @author Paul Ivancsics * @version $Id$ */ public class KeyStoreUtils { - - /** - * JAVA KeyStore - */ - private static final String KEYSTORE_TYPE_JKS = "JKS"; - - /** - * PKCS12 KeyStore - */ - private static final String KEYSTORE_TYPE_PKCS12 = "PKCS12"; - - + + /** + * JAVA KeyStore. + */ + private static final String KEYSTORE_TYPE_JKS = "JKS"; + + /** + * PKCS12 KeyStore. + */ + private static final String KEYSTORE_TYPE_PKCS12 = "PKCS12"; + + /** * Loads a key store from file. - * + * * @param keystoreType key store type * @param urlString URL of key store * @param password password protecting the key store @@ -70,20 +62,35 @@ public class KeyStoreUtils { * @throws IOException thrown while reading the key store from file * @throws GeneralSecurityException thrown while creating the key store */ - public static KeyStore loadKeyStore( - String keystoreType, - String urlString, - String password) - throws IOException, GeneralSecurityException { - - URL keystoreURL = new URL(urlString); - InputStream in = keystoreURL.openStream(); + public static KeyStore loadKeyStore(final String keystoreType, final String urlString, + final String password) throws IOException, GeneralSecurityException { + + final URL keystoreUrl = new URL(urlString); + final InputStream in = keystoreUrl.openStream(); return loadKeyStore(keystoreType, in, password); } + /** - * Loads a key store from an InputStream, and - * closes the InputStream. - * + * Load a KeyStore from Filesystem. + * + * @param keyStorePath Path to KeyStore + * @param password KeyStore password + * @return KeyStore + * @throws KeyStoreException In case of a keystore error + * @throws IOException In case of a general read error + */ + public static KeyStore loadKeyStore(final String keyStorePath, final String password) + throws KeyStoreException, IOException { + final URL keystoreUrl = new URL(keyStorePath); + final InputStream in = keystoreUrl.openStream(); + final InputStream isBuffered = new BufferedInputStream(in); + return loadKeyStore(isBuffered, password); + + } + + /** + * Loads a key store from an InputStream, and closes the InputStream. + * * @param keystoreType key store type * @param in input stream * @param password password protecting the key store @@ -91,39 +98,63 @@ public class KeyStoreUtils { * @throws IOException thrown while reading the key store from the stream * @throws GeneralSecurityException thrown while creating the key store */ - public static KeyStore loadKeyStore( - String keystoreType, - InputStream in, - String password) - throws IOException, GeneralSecurityException { + public static KeyStore loadKeyStore(final String keystoreType, final InputStream in, + final String password) throws IOException, GeneralSecurityException { char[] chPassword = null; - if (password != null) + if (password != null) { chPassword = password.toCharArray(); - KeyStore ks = KeyStore.getInstance(keystoreType); + } + final KeyStore ks = KeyStore.getInstance(keystoreType); ks.load(in, chPassword); in.close(); return ks; } + /** - * Creates a key store from X509 certificate files, aliasing them with - * the index in the String[], starting with "0". - * + * Loads a keyStore without knowing the keyStore type. + * + * @param is input stream + * @param password Password protecting the keyStore + * @return keyStore loaded + * @throws KeyStoreException thrown if keyStore cannot be loaded + * @throws IOException In case of a general error + */ + public static KeyStore loadKeyStore(final InputStream is, final String password) + throws KeyStoreException, IOException { + is.mark(1024 * 1024); + KeyStore ks = null; + try { + try { + ks = loadKeyStore(KEYSTORE_TYPE_PKCS12, is, password); + } catch (final IOException e2) { + is.reset(); + ks = loadKeyStore(KEYSTORE_TYPE_JKS, is, password); + } + } catch (final Exception e) { + e.printStackTrace(); + + } + return ks; + + } + + /** + * Creates a key store from X509 certificate files, aliasing them with the index in the + * String[], starting with "0". + * * @param keyStoreType key store type * @param certFilenames certificate filenames * @return key store created - * @throws IOException thrown while reading the certificates from file - * @throws GeneralSecurityException thrown while creating the key store + * @throws Exception In case of an error */ - public static KeyStore createKeyStore( - String keyStoreType, - String[] certFilenames) - throws IOException, GeneralSecurityException { + public static KeyStore createKeyStore(final String keyStoreType, final String[] certFilenames) + throws Exception { - KeyStore ks = KeyStore.getInstance(keyStoreType); + final KeyStore ks = KeyStore.getInstance(keyStoreType); ks.load(null, null); for (int i = 0; i < certFilenames.length; i++) { - Certificate cert = loadCertificate(certFilenames[i]); + final Certificate cert = loadCertificate(certFilenames[i]); ks.setCertificateEntry("" + i, cert); } return ks; @@ -131,69 +162,36 @@ public class KeyStoreUtils { /** * Loads an X509 certificate from file. + * * @param certFilename filename * @return the certificate loaded - * @throws IOException thrown while reading the certificate from file - * @throws GeneralSecurityException thrown while creating the certificate + * @throws Exception In case of an IO exception */ - private static Certificate loadCertificate(String certFilename) - throws IOException, GeneralSecurityException { + private static Certificate loadCertificate(final String certFilename) + throws Exception { + FileInputStream in = null; + try { + in = new FileInputStream(certFilename); + final CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); + final Certificate cert = certFactory.generateCertificate(in); + in.close(); + return cert; - FileInputStream in = new FileInputStream(certFilename); - CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); - Certificate cert = certFactory.generateCertificate(in); - in.close(); - return cert; + } catch (final Exception e) { + throw e; + + } finally { + if (in != null) { + try { + in.close(); + } catch (final IOException e) { + e.printStackTrace(); + } + + } + } } - - - /** - * Loads a keyStore without knowing the keyStore type - * @param keyStorePath URL to the keyStore - * @param password Password protecting the keyStore - * @return keyStore loaded - * @throws KeyStoreException thrown if keyStore cannot be loaded - * @throws FileNotFoundException - * @throws IOException - */ - public static KeyStore loadKeyStore(String keyStorePath, String password) throws KeyStoreException, IOException{ - - //InputStream is = new FileInputStream(keyStorePath); - URL keystoreURL = new URL(keyStorePath); - InputStream in = keystoreURL.openStream(); - InputStream isBuffered = new BufferedInputStream(in); - return loadKeyStore(isBuffered, password); - - } - - /** - * Loads a keyStore without knowing the keyStore type - * @param in input stream - * @param password Password protecting the keyStore - * @return keyStore loaded - * @throws KeyStoreException thrown if keyStore cannot be loaded - * @throws FileNotFoundException - * @throws IOException - */ -public static KeyStore loadKeyStore(InputStream is, String password) throws KeyStoreException, IOException{ - is.mark(1024*1024); - KeyStore ks = null; - try { - try { - ks = loadKeyStore(KEYSTORE_TYPE_PKCS12, is, password); - } catch (IOException e2) { - is.reset(); - ks = loadKeyStore(KEYSTORE_TYPE_JKS, is, password); - } - } catch(Exception e) { - e.printStackTrace(); - - } - return ks; - - } - - + } diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyValueUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyValueUtils.java index e753f19f..929d2994 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyValueUtils.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/KeyValueUtils.java @@ -1,29 +1,22 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.utils; import java.util.ArrayList; @@ -35,341 +28,347 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; - import javax.annotation.Nonnull; import javax.annotation.Nullable; - import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** + * Utils to operate on Key/Value based configurations. + * * @author tlenz * */ public class KeyValueUtils { - private static final Logger log = LoggerFactory.getLogger(KeyValueUtils.class); - - public static final String KEY_DELIMITER = "."; - public static final String CSV_DELIMITER = ","; - public static final String KEYVVALUEDELIMITER = "="; - public static final String DEFAULT_VALUE = "default"; - - /** - * Convert Java properties into a Map - *

- * Important: The key/values from properties must be of type String! - * - * @param properties - * @return - */ - public static Map convertPropertiesToMap(Properties properties) { - return new HashMap((Map) properties); - - //INFO Java8 solution ;) -// return properties.entrySet().stream().collect( -// Collectors.toMap( -// e -> e.getKey().toString(), -// e -> e.getValue().toString() -// ) -// ); - - } - - /** - * Extract the first child of an input key after a the prefix - * - * @param key Full input key - * @param prefix Prefix - * @return Child key {String} if it exists or null - */ - public static String getFirstChildAfterPrefix(String key, String prefix) { - final String idAfterPrefix = removePrefixFromKey(key, prefix); - if (idAfterPrefix != null) { - final int index = idAfterPrefix.indexOf(KEY_DELIMITER); - if (index > 0) { - final String adding = idAfterPrefix.substring(0, index); - if (!(adding.isEmpty())) { - return adding; - - } - } else if (!(idAfterPrefix.isEmpty())) { - return idAfterPrefix; - - } - - } - return null; - } - - /** - * Extract the prefix from an input key - * - * @param key Full input key - * @param suffix Suffix of this key - * @return Prefix {String} of the key or null if input key does not ends with postfix string - */ - public static String getPrefixFromKey(String key, String suffix) { - if (key != null && suffix != null && key.endsWith(suffix)) { - final String idPreforeSuffix = key.substring(0, key.length()-suffix.length()); - if (idPreforeSuffix.endsWith(KEY_DELIMITER)) - return idPreforeSuffix.substring(0, idPreforeSuffix.length()-1); - else - return idPreforeSuffix; - } - return null; - - } - - /** - * Remove a prefix string from a key - * - * @param key Full input key - * @param prefix Prefix, which should be removed - * @return The suffix of the input key or null if the input does not starts with the prefix - */ - public static String removePrefixFromKey(String key, String prefix) { - if (prefix == null) - prefix = new String(); - - if (key!=null && key.startsWith(prefix)) { - String afterPrefix = key.substring(prefix.length()); - final int index = afterPrefix.indexOf(KEY_DELIMITER); - - if (index == 0) { - afterPrefix = afterPrefix.substring(1); - - } - return afterPrefix; - - } - return null; - } - - /** - * Remove a prefix string from all keys in {Map} of key/value pairs - * - * @param keys Input data of key/value pairs - * @param prefix Prefix which should be removed - * @return {Map} of key/value pairs without prefix in key, but never null - */ - public static Map removePrefixFromKeys(Map keys, String prefix) { - final Map result = new HashMap(); - final Iterator> interator = keys.entrySet().iterator(); - while(interator.hasNext()) { - final Entry el = interator.next(); - final String newKey = removePrefixFromKey(el.getKey(), prefix); - if (StringUtils.isNotEmpty(newKey)) { - result.put(newKey, el.getValue()); - } - } - - return result; - } - - /** - * Get a subset of key/value pairs which starts with a prefix string - * The Prefix is removed from the key - * - * @param keys Input data of key/value pairs - * @param prefix Prefix string - * @return {Map} of key/value pairs without prefix in key, but never null - */ - public static Map getSubSetWithPrefix(Map keys, String prefix) { - return removePrefixFromKeys(keys, prefix); - } - - - /** - * Add a prefix to key/value pairs to make the key absolute according to key namespace convention - * - * @param input Input key/value pairs which should be updated - * @param prefix Key prefix, which should be added if the key is not absolute - * @param absolutIdentifier Key identifier, which indicates an absolute key - * @return {Map} of key/value pairs in which all keys are absolute but never null - */ - public static Map makeKeysAbsolut(Map input, String prefix, String absolutIdentifier) { - final Map result = new HashMap(); - final Iterator> interator = input.entrySet().iterator(); - while(interator.hasNext()) { - final Entry el = interator.next(); - if (!el.getKey().startsWith(absolutIdentifier)) { - //key is not absolute -> add prefix - result.put(prefix - + KEY_DELIMITER - + el.getKey(), - el.getValue()); - - } else { - //key is absolute - result.put(el.getKey(), el.getValue()); - } - } - return result; - } - - /** - * Get the parent key string from an input key - * - * @param key input key - * @return parent key or the empty String if no parent exists - */ - public static String getParentKey(String key) { - if (StringUtils.isNotEmpty(key)) { - final int index = key.lastIndexOf(KEY_DELIMITER); - if (index > 0) { - return key.substring(0, index); - - } - } - - return new String(); - } - - /** - * Find the highest free list counter - * - * @param input Array of list keys - * @param listPrefix {String} prefix of the list - * @return {int} highest free list counter - */ - public static int findNextFreeListCounter(String[] input, - String listPrefix) { - final List counters = new ArrayList(); - if (input == null || input.length == 0) - return 0; - - else { - for (final String key : input) { - final String listIndex = getFirstChildAfterPrefix(key, listPrefix); - counters.add(Integer.parseInt(listIndex)); - - } - Collections.sort(counters); - return counters.get(counters.size()-1) + 1; - } - } - - /** - * Find the highest free list counter - * - * @param keySet {Set} of list keys - * @param listPrefix {String} prefix of the list - * @return {int} highest free list counter - */ - public static int findNextFreeListCounter(Set keySet, - String listPrefix) { - if (keySet.isEmpty()) - return 0; - - final String[] array = new String[keySet.size()]; - keySet.toArray(array); - return findNextFreeListCounter(array, listPrefix); - } - - - /** - * Normalize a CSV encoded list of value of an key/value pair - * - * This method removes all whitespace at the begin or the - * end of CSV values and remove newLine signs at the end of value. - * The ',' is used as list delimiter - * - * @param value CSV encoded input data - * @return normalized CSV encoded data or null if {value} is null or empty - */ - public static String normalizeCSVValueString(String value) { - String normalizedCodes = null; - if (StringUtils.isNotEmpty(value)) { - final String[] codes = value.split(CSV_DELIMITER); - for (final String el: codes) { - if (normalizedCodes == null) - normalizedCodes = StringUtils.chomp(el.trim()); - else - normalizedCodes += "," + StringUtils.chomp(el.trim()); - - } - } - return normalizedCodes; - } - - - /** - * Check a String if it is a comma separated list of values - * - * This method uses the ',' as list delimiter. - * - * @param value CSV encoded input data - * @return true if the input data contains a ',' and has more then 1 list element, otherwise false - */ - public static boolean isCSVValueString(String value) { - if (StringUtils.isNotEmpty(value)) { - final String[] codes = value.split(CSV_DELIMITER); - if (codes.length >= 2) { - if (StringUtils.isNotEmpty(codes[1].trim())) - return true; - - } - } - - return false; - } - - /** - * Convert a CSV list to a List of CSV values - *

- * This method removes all whitespace at the begin or the - * end of CSV values and remove newLine signs at the end of value. - * The ',' is used as list delimiter - * - * @param csv CSV encoded input data - * @return List of CSV normalized values, but never null - */ - @Nonnull - public static List getListOfCSVValues(@Nullable String csv) { - final List list = new ArrayList(); - if (StringUtils.isNotEmpty(csv)) { - final String[] values = csv.split(CSV_DELIMITER); - for (final String el: values) - list.add(el.trim()); - - } - - return list; - } - - /** - * Convert a List of String elements to a Map of Key/Value pairs - *
- * Every List element used as a key/value pair and the '=' sign represents the delimiter between key and value - * - * @param elements List of key/value elements - * @return Map of Key / Value pairs, but never null - */ - public static Map convertListToMap(List elements) { - final Map map = new HashMap(); - for (final String el : elements) { - if (el.contains(KEYVVALUEDELIMITER)) { - final String[] split = el.split(KEYVVALUEDELIMITER); - map.put(split[0], split[1]); - - } else - log.debug("Key/Value Mapper: '" + el + "' contains NO '='. Ignore it."); - - } - - return map; - } - - /** - * This method remove all newline delimiter (\n or \r\n) from input data - * - * @param value Input String - * @return Input String without newline characters - */ - public static String removeAllNewlineFromString(String value) { - return value.replaceAll("(\\t|\\r?\\n)+", ""); - - } - + private static final Logger log = LoggerFactory.getLogger(KeyValueUtils.class); + + public static final String KEY_DELIMITER = "."; + public static final String CSV_DELIMITER = ","; + public static final String KEYVVALUEDELIMITER = "="; + public static final String DEFAULT_VALUE = "default"; + + /** + * Convert Java properties into a Map String/String. + *
+ * Important: The key/values from properties must be of type String! + * + * @param properties Java {@link Properties} that should be converted + * @return + */ + public static Map convertPropertiesToMap(final Properties properties) { + return new HashMap((Map) properties); + + // INFO Java8 solution ;) + // return properties.entrySet().stream().collect( + // Collectors.toMap( + // e -> e.getKey().toString(), + // e -> e.getValue().toString() + // ) + // ); + + } + + /** + * Extract the first child of an input key after a the prefix. + * + * @param key Full input key + * @param prefix Prefix + * @return Child key {String} if it exists or null + */ + public static String getFirstChildAfterPrefix(final String key, final String prefix) { + final String idAfterPrefix = removePrefixFromKey(key, prefix); + if (idAfterPrefix != null) { + final int index = idAfterPrefix.indexOf(KEY_DELIMITER); + if (index > 0) { + final String adding = idAfterPrefix.substring(0, index); + if (!(adding.isEmpty())) { + return adding; + + } + } else if (!(idAfterPrefix.isEmpty())) { + return idAfterPrefix; + + } + + } + return null; + } + + /** + * Extract the prefix from an input key. + * + * @param key Full input key + * @param suffix Suffix of this key + * @return Prefix {String} of the key or null if input key does not ends with postfix string + */ + public static String getPrefixFromKey(final String key, final String suffix) { + if (key != null && suffix != null && key.endsWith(suffix)) { + final String idPreforeSuffix = key.substring(0, key.length() - suffix.length()); + if (idPreforeSuffix.endsWith(KEY_DELIMITER)) { + return idPreforeSuffix.substring(0, idPreforeSuffix.length() - 1); + } else { + return idPreforeSuffix; + } + } + return null; + + } + + /** + * Remove a prefix string from a key. + * + * @param key Full input key + * @param prefix Prefix, which should be removed + * @return The suffix of the input key or null if the input does not starts with the prefix + */ + public static String removePrefixFromKey(final String key, String prefix) { + if (prefix == null) { + prefix = StringUtils.EMPTY; + + } + + if (key != null && key.startsWith(prefix)) { + String afterPrefix = key.substring(prefix.length()); + final int index = afterPrefix.indexOf(KEY_DELIMITER); + + if (index == 0) { + afterPrefix = afterPrefix.substring(1); + + } + return afterPrefix; + + } + return null; + } + + /** + * Remove a prefix string from all keys in Map String/String of key/value pairs. + * + * @param keys Input data of key/value pairs + * @param prefix Prefix which should be removed + * @return Map String/String of key/value pairs without prefix in key, but never null + */ + public static Map removePrefixFromKeys(final Map keys, + final String prefix) { + final Map result = new HashMap<>(); + final Iterator> interator = keys.entrySet().iterator(); + while (interator.hasNext()) { + final Entry el = interator.next(); + final String newKey = removePrefixFromKey(el.getKey(), prefix); + if (StringUtils.isNotEmpty(newKey)) { + result.put(newKey, el.getValue()); + } + } + + return result; + } + + /** + * Get a subset of key/value pairs which starts with a prefix string The Prefix is removed from + * the key. + * + * @param keys Input data of key/value pairs + * @param prefix Prefix string + * @return Map String/String of key/value pairs without prefix in key, but never null + */ + public static Map getSubSetWithPrefix(final Map keys, + final String prefix) { + return removePrefixFromKeys(keys, prefix); + } + + + /** + * Add a prefix to key/value pairs to make the key absolute according to key namespace convention. + * + * @param input Input key/value pairs which should be updated + * @param prefix Key prefix, which should be added if the key is not absolute + * @param absolutIdentifier Key identifier, which indicates an absolute key + * @return Map String/String of key/value pairs in which all keys are absolute but never null + */ + public static Map makeKeysAbsolut(final Map input, + final String prefix, final String absolutIdentifier) { + final Map result = new HashMap<>(); + final Iterator> interator = input.entrySet().iterator(); + while (interator.hasNext()) { + final Entry el = interator.next(); + if (!el.getKey().startsWith(absolutIdentifier)) { + // key is not absolute -> add prefix + result.put(prefix + KEY_DELIMITER + el.getKey(), el.getValue()); + + } else { + // key is absolute + result.put(el.getKey(), el.getValue()); + } + } + return result; + } + + /** + * Get the parent key string from an input key. + * + * @param key input key + * @return parent key or the empty String if no parent exists + */ + public static String getParentKey(final String key) { + if (StringUtils.isNotEmpty(key)) { + final int index = key.lastIndexOf(KEY_DELIMITER); + if (index > 0) { + return key.substring(0, index); + + } + } + + return StringUtils.EMPTY; + } + + /** + * Find the highest free list counter. + * + * @param input Array of list keys + * @param listPrefix {String} prefix of the list + * @return {int} highest free list counter + */ + public static int findNextFreeListCounter(final String[] input, final String listPrefix) { + final List counters = new ArrayList<>(); + if (input == null || input.length == 0) { + return 0; + } else { + for (final String key : input) { + final String listIndex = getFirstChildAfterPrefix(key, listPrefix); + counters.add(Integer.parseInt(listIndex)); + + } + Collections.sort(counters); + return counters.get(counters.size() - 1) + 1; + } + } + + /** + * Find the highest free list counter. + * + * @param keySet Set of list keys + * @param listPrefix {String} prefix of the list + * @return {int} highest free list counter + */ + public static int findNextFreeListCounter(final Set keySet, final String listPrefix) { + if (keySet.isEmpty()) { + return 0; + } + + final String[] array = new String[keySet.size()]; + keySet.toArray(array); + return findNextFreeListCounter(array, listPrefix); + } + + + /** + * Normalize a CSV encoded list of value of an key/value pair. + * + *

+ * This method removes all whitespace at the begin or the end of CSV values and remove newLine + * signs at the end of value. The ',' is used as list delimiter + *

+ * + * @param value CSV encoded input data + * @return normalized CSV encoded data or null if {value} is null or empty + */ + public static String normalizeCsvValueString(final String value) { + String normalizedCodes = null; + if (StringUtils.isNotEmpty(value)) { + final String[] codes = value.split(CSV_DELIMITER); + for (final String el : codes) { + if (normalizedCodes == null) { + normalizedCodes = StringUtils.chomp(el.trim()); + } else { + normalizedCodes += "," + StringUtils.chomp(el.trim()); + } + + } + } + return normalizedCodes; + } + + + /** + * Check a String if it is a comma separated list of values. + * + *

+ * This method uses the ',' as list delimiter. + *

+ * + * @param value CSV encoded input data + * @return true if the input data contains a ',' and has more then 1 list element, otherwise false + */ + public static boolean isCsvValueString(final String value) { + if (StringUtils.isNotEmpty(value)) { + final String[] codes = value.split(CSV_DELIMITER); + if (codes.length >= 2 + && StringUtils.isNotEmpty(codes[1].trim())) { + return true; + + } + } + + return false; + } + + /** + * Convert a CSV list to a List of CSV values.
+ *
+ * This method removes all whitespace at the begin or the end of CSV values and remove newLine + * signs at the end of value. The ',' is used as list delimiter + * + * @param csv CSV encoded input data + * @return List of CSV normalized values, but never null + */ + @Nonnull + public static List getListOfCsvValues(@Nullable final String csv) { + final List list = new ArrayList<>(); + if (StringUtils.isNotEmpty(csv)) { + final String[] values = csv.split(CSV_DELIMITER); + for (final String el : values) { + list.add(el.trim()); + } + + } + + return list; + } + + /** + * Convert a List of String elements to a Map of Key/Value pairs.
+ * Every List element used as a key/value pair and the '=' sign represents the delimiter between + * key and value + * + * @param elements List of key/value elements + * @return Map of Key / Value pairs, but never null + */ + public static Map convertListToMap(final List elements) { + final Map map = new HashMap<>(); + for (final String el : elements) { + if (el.contains(KEYVVALUEDELIMITER)) { + final String[] split = el.split(KEYVVALUEDELIMITER); + map.put(split[0], split[1]); + + } else { + log.debug("Key/Value Mapper: '" + el + "' contains NO '='. Ignore it."); + } + + } + + return map; + } + + /** + * This method remove all newline delimiter (\n or \r\n) from input data. + * + * @param value Input String + * @return Input String without newline characters + */ + public static String removeAllNewlineFromString(final String value) { + return value.replaceAll("(\\t|\\r?\\n)+", ""); + + } + } diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeIteratorAdapter.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeIteratorAdapter.java index ec57b92a..755c4431 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeIteratorAdapter.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeIteratorAdapter.java @@ -1,92 +1,79 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.utils; import java.util.ListIterator; - import org.w3c.dom.DOMException; import org.w3c.dom.Node; import org.w3c.dom.traversal.NodeFilter; import org.w3c.dom.traversal.NodeIterator; /** - * A NodeIterator implementation based on a - * ListIterator. - * + * A NodeIterator implementation based on a ListIterator. + * * @see java.util.ListIterator * @see org.w3c.dom.traversal.NodeIterator - * + * */ public class NodeIteratorAdapter implements NodeIterator { /** The ListIterator to wrap. */ - private ListIterator nodeIterator; + private final ListIterator nodeIterator; /** * Create a new NodeIteratorAdapter. + * * @param nodeIterator The ListIterator to iterate over. */ - public NodeIteratorAdapter(ListIterator nodeIterator) { + public NodeIteratorAdapter(final ListIterator nodeIterator) { this.nodeIterator = nodeIterator; } - /** - * @see org.w3c.dom.traversal.NodeIterator#getRoot() - */ + + @Override public Node getRoot() { return null; } - /** - * @see org.w3c.dom.traversal.NodeIterator#getWhatToShow() - */ + + @Override public int getWhatToShow() { return NodeFilter.SHOW_ALL; } - /** - * @see org.w3c.dom.traversal.NodeIterator#getFilter() - */ + + @Override public NodeFilter getFilter() { return null; } - /** - * @see org.w3c.dom.traversal.NodeIterator#getExpandEntityReferences() - */ + + @Override public boolean getExpandEntityReferences() { return false; } - /** - * @see org.w3c.dom.traversal.NodeIterator#nextNode() - */ + + @Override public Node nextNode() throws DOMException { if (nodeIterator.hasNext()) { return (Node) nodeIterator.next(); @@ -94,9 +81,8 @@ public class NodeIteratorAdapter implements NodeIterator { return null; } - /** - * @see org.w3c.dom.traversal.NodeIterator#previousNode() - */ + + @Override public Node previousNode() throws DOMException { if (nodeIterator.hasPrevious()) { return (Node) nodeIterator.previous(); @@ -104,10 +90,10 @@ public class NodeIteratorAdapter implements NodeIterator { return null; } - /** - * @see org.w3c.dom.traversal.NodeIterator#detach() - */ + + @Override public void detach() { + } } diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeListAdapter.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeListAdapter.java index 69045aaa..a942f75e 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeListAdapter.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/NodeListAdapter.java @@ -1,68 +1,58 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.utils; import java.util.List; - import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * A NodeList implementation based on a List. - * + * * @see java.util.List * @see org.w3c.dom.NodeList */ public class NodeListAdapter implements NodeList { /** The List to wrap. */ - private List nodeList; - + private final List nodeList; + /** * Create a new NodeListAdapter. - * - * @param nodeList The List containing the nodes. + * + * @param nodeList The List containing the nodes. */ - public NodeListAdapter(List nodeList) { + public NodeListAdapter(final List nodeList) { this.nodeList = nodeList; } - /** - * @see org.w3c.dom.NodeList#item(int) - */ - public Node item(int index) { + + @Override + public Node item(final int index) { return (Node) nodeList.get(index); } - /** - * @see org.w3c.dom.NodeList#getLength() - */ + + @Override public int getLength() { return nodeList.size(); } diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/Random.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/Random.java index e236b3a9..14d54b0b 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/Random.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/Random.java @@ -1,176 +1,188 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. + */ package at.gv.egiz.eaaf.core.impl.utils; +import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; - +import at.gv.egiz.eaaf.core.impl.idp.process.support.SecureRandomHolder; import org.apache.commons.codec.binary.Hex; import org.apache.commons.lang3.ArrayUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import at.gv.egiz.eaaf.core.impl.idp.process.support.SecureRandomHolder; - /** - * Random number generator used to generate ID's + * Random number generator used to generate ID's. + * * @author Paul Ivancsics * @version $Id$ */ public class Random { - private static final Logger log = LoggerFactory.getLogger(Random.class); - - private final static char[] allowedPreFix = - {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z', - 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}; - private static final DateFormat dateFormater = new SimpleDateFormat("yyyyddMM"); - - /** random number generator used */ - private static SecureRandom random; - //private static SeedGenerator seedgenerator; - - static { - try { - random = SecureRandom.getInstance("SHA256PRNG-FIPS186"); - - } catch (NoSuchAlgorithmException e) { - log.warn("Can NOT initialize SecureRandom with: 'SHA256PRNG-FIPS186'. Use 'StrongSecureRandom' as backup"); - random = SecureRandomHolder.getInstance(); - - } - - - //random = iaik.security.random.SHA256FIPS186Random.getDefault(); - } - - /** - * Generate a unique process reference-value [160bit], which always starts with a letter - *
- * This unique ID consists of single letter, a 64bit date String[yyyyddMM], - * and a 88bit random value. - * - * @return 160bit ID, which is hex encoded - */ - public static String nextProcessReferenceValue() { - //pre-process all three parts of a unique reference value - String now = dateFormater.format(new Date()); //8 bytes = 64bit - byte[] randValue = nextByteRandom(11); - char preFix = allowedPreFix[Math.abs(random.nextInt() % allowedPreFix.length)]; - - //generate ID - String returnValue = preFix + new String(Hex.encodeHex(ArrayUtils.addAll(now.getBytes(), randValue))); // 20 bytes = 160 bits - if (returnValue.length() > 40) - return returnValue.substring(0, 40); - else - return returnValue; - - } - - - - /** - * Creates a new random number [256bit], and encode it as hex value. - * - * @return random hex encoded value [256bit] - */ - public static String nextHexRandom32() { - return new String(Hex.encodeHex(nextByteRandom(32))); // 32 bytes = 256 bits - - } - - /** - * Creates a new random number [128bit], and encode it as hex value. - * - * @return random hex encoded value [128bit] - */ - public static String nextHexRandom16() { - return new String(Hex.encodeHex(nextByteRandom(16))); // 16 bytes = 128 bits - - } - - /** - * Creates a new random number [64bit], to be used as an ID. - * - * @return random long as a String [64bit] - */ - public static String nextLongRandom() { - return "".concat(String.valueOf(Math.abs(generateLongRandom(32)))); // 32 bytes = 256 bits - - } - + private static final Logger log = LoggerFactory.getLogger(Random.class); + + private static final char[] allowedPreFix = + {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', + 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; + + /** random number generator used. */ + private static SecureRandom random; + // private static SeedGenerator seedgenerator; + + static { + try { + random = SecureRandom.getInstance("SHA256PRNG-FIPS186"); + + } catch (final NoSuchAlgorithmException e) { + log.warn( + "Can NOT initialize SecureRandom with: 'SHA256PRNG-FIPS186'. Use 'StrongSecureRandom' as backup"); + random = SecureRandomHolder.getInstance(); + + } + + + // random = iaik.security.random.SHA256FIPS186Random.getDefault(); + } + + /** + * Generate a unique process reference-value [160bit], which always starts with a letter
+ * This unique ID consists of single letter, a 64bit date String[yyyyddMM], and a 88bit random + * value. + * + * @return 160bit ID, which is hex encoded + */ + public static String nextProcessReferenceValue() { + // pre-process all three parts of a unique reference value + final DateFormat dateFormater = new SimpleDateFormat("yyyyddMM"); + final String now = dateFormater.format(new Date()); // 8 bytes = 64bit + final byte[] randValue = nextByteRandom(11); + final char preFix = allowedPreFix[Math.abs(random.nextInt() % allowedPreFix.length)]; + + // generate ID + String returnValue; + try { + returnValue = preFix + new String(Hex.encodeHex(ArrayUtils.addAll(now.getBytes("UTF-8"), randValue))); + + // 20 bytes = 160 bits + if (returnValue.length() > 40) { + return returnValue.substring(0, 40); + } else { + return returnValue; + } + + } catch (final UnsupportedEncodingException e) { + throw new RuntimeException(e); + + } + + + + } + + + + /** + * Creates a new random number [256bit], and encode it as hex value. + * + * @return random hex encoded value [256bit] + */ + public static String nextHexRandom32() { + return new String(Hex.encodeHex(nextByteRandom(32))); // 32 bytes = 256 bits + + } + + /** + * Creates a new random number [128bit], and encode it as hex value. + * + * @return random hex encoded value [128bit] + */ + public static String nextHexRandom16() { + return new String(Hex.encodeHex(nextByteRandom(16))); // 16 bytes = 128 bits + + } + + /** + * Creates a new random number [64bit], to be used as an ID. + * + * @return random long as a String [64bit] + */ + public static String nextLongRandom() { + return "".concat(String.valueOf(Math.abs(generateLongRandom(32)))); // 32 bytes = 256 bits + + } + /** * Creates a new random number, to be used as an ID. - * + * * @return random long as a String [64bit] */ - @Deprecated - public static String nextRandom() { - long l = ByteBuffer.wrap(nextByteRandom(32)).getLong(); // 32 bytes = 256 bits - return "" + Math.abs(l); - + @Deprecated + public static String nextRandom() { + final long l = ByteBuffer.wrap(nextByteRandom(32)).getLong(); // 32 bytes = 256 bits + return "" + Math.abs(l); + } - -/** - * Creates a new random byte[] - * - * @param size Size of random number in byte - * @return - */ -public static byte[] nextBytes(int size) { - return nextByteRandom(size); - -} - + + /** + * Creates a new random byte[]. + * + * @param size Size of random number in byte + * @return + */ + public static byte[] nextBytes(final int size) { + return nextByteRandom(size); + + } + + /** + * initialize random-number generator. + */ public static void seedRandom() { - //TODO: implement reflection on IAIK Seed generator -// seedgenerator = iaik.security.random.AutoSeedGenerator.getDefault(); -// if (seedgenerator.seedAvailable()) -// random.setSeed(seedgenerator.getSeed()); - - random.setSeed(System.nanoTime()); + // TODO: implement reflection on IAIK Seed generator + // seedgenerator = iaik.security.random.AutoSeedGenerator.getDefault(); + // if (seedgenerator.seedAvailable()) + // random.setSeed(seedgenerator.getSeed()); + + random.setSeed(System.nanoTime()); } - - private static long generateLongRandom(int size) { - return ByteBuffer.wrap(nextByteRandom(size)).getLong(); - } - + + private static long generateLongRandom(final int size) { + return ByteBuffer.wrap(nextByteRandom(size)).getLong(); + } + /** - * Generate a new random number - * + * Generate a new random number. + * * @param size Size of random number in byte * @return */ - private static synchronized byte[] nextByteRandom(int size) { - byte[] b = new byte[size]; - random.nextBytes(b); - return b; - + private static synchronized byte[] nextByteRandom(final int size) { + final byte[] b = new byte[size]; + random.nextBytes(b); + return b; + } } diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java index f0ef9b38..ee88c4bb 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SecurePendingRequestIdGenerationStrategy.java @@ -1,19 +1,24 @@ package at.gv.egiz.eaaf.core.impl.utils; import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; import java.util.Arrays; import java.util.Base64; - import javax.annotation.PostConstruct; import javax.crypto.Mac; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; - +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.api.utils.IPendingRequestIdGenerationStrategy; +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.core.exceptions.EaafIllegalStateException; +import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException; import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; import org.joda.time.DurationFieldType; @@ -25,190 +30,209 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; -import at.gv.egiz.eaaf.core.api.idp.IConfiguration; -import at.gv.egiz.eaaf.core.api.utils.IPendingRequestIdGenerationStrategy; -import at.gv.egiz.eaaf.core.exceptions.EAAFConfigurationException; -import at.gv.egiz.eaaf.core.exceptions.EAAFException; -import at.gv.egiz.eaaf.core.exceptions.EAAFIllegalStateException; -import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException; - /** - * PendingRequestId generation strategy based on signed tokens that facilitates extended token validation - * + * PendingRequestId generation strategy based on signed tokens that facilitates extended token + * validation. + * * @author tlenz * */ -public class SecurePendingRequestIdGenerationStrategy implements IPendingRequestIdGenerationStrategy { - private static final Logger log = LoggerFactory.getLogger(SecurePendingRequestIdGenerationStrategy.class); - - @Autowired(required=true) IConfiguration baseConfig; - - public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET = "core.pendingrequestid.digist.secret"; - public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_ALGORITHM = "core.pendingrequestid.digist.algorithm"; - public static final String CONFIG_PROP_PENDINGREQUESTID_MAX_LIFETIME = "core.pendingrequestid.maxlifetime"; - - public static final String DEFAULT_PENDINGREQUESTID_DIGIST_ALGORITHM = "HmacSHA256"; - public static final String DEFAULT_PENDINGREQUESTID_MAX_LIFETIME = "300"; - - private static final int ENCODED_TOKEN_PARTS = 3; - private static final String TOKEN_SEPARATOR = "|"; - private static final DateTimeFormatter TOKEN_TEXTUAL_DATE_FORMAT = - DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss SSS"); - - private int maxPendingRequestIdLifeTime = 300; - private final int maxPendingReqIdSize = 1024; - private String digistAlgorithm = null; - private SecretKey key = null; - private final byte[] salt = "notRequiredInThisScenario".getBytes(); - - @Override - public String generateExternalPendingRequestId() throws EAAFException { - try { - final String toSign = buildInternalToken(Random.nextLongRandom(), DateTime.now()); - final StringBuilder externalPendingRequestId= new StringBuilder(); - externalPendingRequestId.append(toSign); - externalPendingRequestId.append(TOKEN_SEPARATOR); - externalPendingRequestId.append(Base64.getEncoder().encodeToString(calculateHMAC(toSign))); - return Base64.getUrlEncoder().encodeToString(externalPendingRequestId.toString().getBytes("UTF-8")); - - } catch (final UnsupportedEncodingException e) { - throw new EAAFException("internal.99", new Object[] {e.getMessage()}, e); - - } - - } - - @Override - public String getPendingRequestIdWithOutChecks(String externalPendingReqId) throws PendingReqIdValidationException { - final String[] tokenElements = extractTokens(externalPendingReqId); - return tokenElements[1]; - - } - - @Override - public String validateAndGetPendingRequestId(String externalPendingReqId) throws PendingReqIdValidationException { - try { - final String[] tokenElements = extractTokens(externalPendingReqId); - final String internalPendingReqId = tokenElements[1]; - final DateTime timeStamp = TOKEN_TEXTUAL_DATE_FORMAT.parseDateTime(tokenElements[0]); - - log.trace("Checking HMAC from externalPendingReqId ... "); - final byte[] tokenDigest = Base64.getDecoder().decode(tokenElements[2]); - final byte[] refDigist = calculateHMAC(buildInternalToken(internalPendingReqId, timeStamp)); - if (!Arrays.equals(tokenDigest, refDigist)) { - log.warn("Digest of Token does NOT match"); - log.debug("Token: {} | Ref: {}", tokenDigest, refDigist); - throw new PendingReqIdValidationException(null, "Digest of pendingRequestId does NOT match"); - - } - log.debug("PendingRequestId HMAC digest check successful"); - - log.trace("Checking valid period ... "); - final DateTime now = DateTime.now(); - if (timeStamp.withFieldAdded( - DurationFieldType.seconds(), maxPendingRequestIdLifeTime).isBefore(now)) { - log.warn("Token exceeds the valid period"); - log.debug("Token: {} | Now: {}", timeStamp, now ); - throw new PendingReqIdValidationException(internalPendingReqId, "PendingRequestId exceeds the valid period"); - - } - log.debug("Token valid-period check successful"); - - return internalPendingReqId; - - - } catch (final IllegalArgumentException | EAAFIllegalStateException e) { - log.warn("Token is NOT a valid String. Msg: {}", e.getMessage()); - log.debug("TokenValue: {}", externalPendingReqId); - throw new PendingReqIdValidationException(null, "PendingReqId is NOT a valid String", e); - - } - } - - @NonNull - private String[] extractTokens(@Nullable String externalPendingReqId) throws PendingReqIdValidationException { - if (StringUtils.isEmpty(externalPendingReqId)) { - log.info("PendingReqId is 'null' or empty"); - throw new PendingReqIdValidationException(null, "PendingReqId is 'null' or empty"); - - } - - log.trace("RAW external pendingReqId: {}", externalPendingReqId); - final byte[] externalPendingReqIdBytes = Base64.getUrlDecoder().decode(externalPendingReqId); - - if (externalPendingReqIdBytes.length > maxPendingReqIdSize) { - log.warn("pendingReqId size exceeds {}", maxPendingReqIdSize); - throw new PendingReqIdValidationException(null, "pendingReqId exceeds max.size: " + maxPendingReqIdSize); - - } - - final String stringToken = new String(externalPendingReqIdBytes); - if (StringUtils.countMatches(stringToken, TOKEN_SEPARATOR) == ENCODED_TOKEN_PARTS - 1) { - final String[] tokenElements = StringUtils.split(stringToken, - TOKEN_SEPARATOR, ENCODED_TOKEN_PARTS); - return tokenElements; - - } else { - log.warn("PendingRequestId has an unvalid format"); - log.debug("PendingRequestId: {}", stringToken); - throw new PendingReqIdValidationException(null, "PendingReqId has an unvalid format"); - - } - - } - - - @PostConstruct - private void initialize() throws EAAFConfigurationException { - log.debug("Initializing " + this.getClass().getName() + " ... "); - - final String pendingReqIdDigistSecret = baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET); - if (StringUtils.isEmpty(pendingReqIdDigistSecret)) - throw new EAAFConfigurationException("config.08", new Object[] {CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET}); - - digistAlgorithm = baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_ALGORITHM, DEFAULT_PENDINGREQUESTID_DIGIST_ALGORITHM); - - maxPendingRequestIdLifeTime = Integer.valueOf( - baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_MAX_LIFETIME, DEFAULT_PENDINGREQUESTID_MAX_LIFETIME)); - - try { - final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WITHHMACSHA256"); - final KeySpec spec = new PBEKeySpec(pendingReqIdDigistSecret.toCharArray(), salt, 10000, 128); - key = keyFactory.generateSecret(spec); - - - } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { - log.error("Can NOT initialize TokenService with configuration object", e); - throw new EAAFConfigurationException("config.09", - new Object[] { CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET, - "Can NOT generate HMAC key"}, - e); - - } - - log.info(this.getClass().getName() + " initialized with digistAlg: {} and maxLifeTime: {}", digistAlgorithm, maxPendingRequestIdLifeTime); - - } - - private String buildInternalToken(String internalPendingReqId, DateTime now) { - return new StringBuilder() - .append(TOKEN_TEXTUAL_DATE_FORMAT.print(now)) - .append(TOKEN_SEPARATOR) - .append(internalPendingReqId).toString(); - } - - private byte[] calculateHMAC(String toSign) throws EAAFIllegalStateException { - try { - final Mac mac = Mac.getInstance(digistAlgorithm); - mac.init(key); - return mac.doFinal(toSign.getBytes("UTF-8")); - - } catch (UnsupportedEncodingException | NoSuchAlgorithmException | InvalidKeyException e) { - log.error("Can NOT generate secure pendingRequestId", e); - throw new EAAFIllegalStateException(new Object[] {"Can NOT caluclate digist for secure pendingRequestId"}, e); - - } - - } +public class SecurePendingRequestIdGenerationStrategy + implements IPendingRequestIdGenerationStrategy { + private static final Logger log = + LoggerFactory.getLogger(SecurePendingRequestIdGenerationStrategy.class); + + @Autowired(required = true) + IConfiguration baseConfig; + + public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET = + "core.pendingrequestid.digist.secret"; + public static final String CONFIG_PROP_PENDINGREQUESTID_DIGIST_ALGORITHM = + "core.pendingrequestid.digist.algorithm"; + public static final String CONFIG_PROP_PENDINGREQUESTID_MAX_LIFETIME = + "core.pendingrequestid.maxlifetime"; + + public static final String DEFAULT_PENDINGREQUESTID_DIGIST_ALGORITHM = "HmacSHA256"; + public static final String DEFAULT_PENDINGREQUESTID_MAX_LIFETIME = "300"; + + private static final int ENCODED_TOKEN_PARTS = 3; + private static final String TOKEN_SEPARATOR = "|"; + private static final DateTimeFormatter TOKEN_TEXTUAL_DATE_FORMAT = + DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss SSS"); + + private int maxPendingRequestIdLifeTime = 300; + private final int maxPendingReqIdSize = 1024; + private String digistAlgorithm = null; + private SecretKey key = null; + private final byte[] salt = "notRequiredInThisScenario".getBytes(Charset.defaultCharset()); + + @Override + public String generateExternalPendingRequestId() throws EaafException { + try { + final String toSign = buildInternalToken(Random.nextLongRandom(), DateTime.now()); + final StringBuilder externalPendingRequestId = new StringBuilder(); + externalPendingRequestId.append(toSign); + externalPendingRequestId.append(TOKEN_SEPARATOR); + externalPendingRequestId.append(Base64.getEncoder().encodeToString(calculateHmac(toSign))); + return Base64.getUrlEncoder() + .encodeToString(externalPendingRequestId.toString().getBytes("UTF-8")); + + } catch (final UnsupportedEncodingException e) { + throw new EaafException("internal.99", new Object[] {e.getMessage()}, e); + + } + + } + + @Override + public String getPendingRequestIdWithOutChecks(final String externalPendingReqId) + throws PendingReqIdValidationException { + try { + final String[] tokenElements = extractTokens(externalPendingReqId); + return tokenElements[1]; + + } catch (final UnsupportedEncodingException e) { + throw new RuntimeException(e); + + } + } + + @Override + public String validateAndGetPendingRequestId(final String externalPendingReqId) + throws PendingReqIdValidationException { + try { + final String[] tokenElements = extractTokens(externalPendingReqId); + final String internalPendingReqId = tokenElements[1]; + final DateTime timeStamp = TOKEN_TEXTUAL_DATE_FORMAT.parseDateTime(tokenElements[0]); + + log.trace("Checking HMAC from externalPendingReqId ... "); + final byte[] tokenDigest = Base64.getDecoder().decode(tokenElements[2]); + final byte[] refDigist = calculateHmac(buildInternalToken(internalPendingReqId, timeStamp)); + if (!Arrays.equals(tokenDigest, refDigist)) { + log.warn("Digest of Token does NOT match"); + log.debug("Token: {} | Ref: {}", tokenDigest, refDigist); + throw new PendingReqIdValidationException(null, + "Digest of pendingRequestId does NOT match"); + + } + log.debug("PendingRequestId HMAC digest check successful"); + + log.trace("Checking valid period ... "); + final DateTime now = DateTime.now(); + if (timeStamp.withFieldAdded(DurationFieldType.seconds(), maxPendingRequestIdLifeTime) + .isBefore(now)) { + log.warn("Token exceeds the valid period"); + log.debug("Token: {} | Now: {}", timeStamp, now); + throw new PendingReqIdValidationException(internalPendingReqId, + "PendingRequestId exceeds the valid period"); + + } + log.debug("Token valid-period check successful"); + + return internalPendingReqId; + + + } catch (final IllegalArgumentException | EaafIllegalStateException e) { + log.warn("Token is NOT a valid String. Msg: {}", e.getMessage()); + log.debug("TokenValue: {}", externalPendingReqId); + throw new PendingReqIdValidationException(null, "PendingReqId is NOT a valid String", e); + + } catch (final UnsupportedEncodingException e) { + throw new RuntimeException(e); + + } + } + + @NonNull + private String[] extractTokens(@Nullable final String externalPendingReqId) + throws PendingReqIdValidationException, UnsupportedEncodingException { + if (StringUtils.isEmpty(externalPendingReqId)) { + log.info("PendingReqId is 'null' or empty"); + throw new PendingReqIdValidationException(null, "PendingReqId is 'null' or empty"); + + } + + log.trace("RAW external pendingReqId: {}", externalPendingReqId); + final byte[] externalPendingReqIdBytes = Base64.getUrlDecoder().decode(externalPendingReqId); + + if (externalPendingReqIdBytes.length > maxPendingReqIdSize) { + log.warn("pendingReqId size exceeds {}", maxPendingReqIdSize); + throw new PendingReqIdValidationException(null, + "pendingReqId exceeds max.size: " + maxPendingReqIdSize); + + } + + final String stringToken = new String(externalPendingReqIdBytes, "UTF-8"); + if (StringUtils.countMatches(stringToken, TOKEN_SEPARATOR) == ENCODED_TOKEN_PARTS - 1) { + final String[] tokenElements = + StringUtils.split(stringToken, TOKEN_SEPARATOR, ENCODED_TOKEN_PARTS); + return tokenElements; + + } else { + log.warn("PendingRequestId has an unvalid format"); + log.debug("PendingRequestId: {}", stringToken); + throw new PendingReqIdValidationException(null, "PendingReqId has an unvalid format"); + + } + + } + + + @PostConstruct + private void initialize() throws EaafConfigurationException { + log.debug("Initializing " + this.getClass().getName() + " ... "); + + final String pendingReqIdDigistSecret = + baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET); + if (StringUtils.isEmpty(pendingReqIdDigistSecret)) { + throw new EaafConfigurationException("config.08", + new Object[] {CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET}); + } + + digistAlgorithm = baseConfig.getBasicConfiguration( + CONFIG_PROP_PENDINGREQUESTID_DIGIST_ALGORITHM, DEFAULT_PENDINGREQUESTID_DIGIST_ALGORITHM); + + maxPendingRequestIdLifeTime = + Integer.parseInt(baseConfig.getBasicConfiguration(CONFIG_PROP_PENDINGREQUESTID_MAX_LIFETIME, + DEFAULT_PENDINGREQUESTID_MAX_LIFETIME)); + + try { + final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WITHHMACSHA256"); + final KeySpec spec = new PBEKeySpec(pendingReqIdDigistSecret.toCharArray(), salt, 10000, 128); + key = keyFactory.generateSecret(spec); + + + } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { + log.error("Can NOT initialize TokenService with configuration object", e); + throw new EaafConfigurationException("config.09", + new Object[] {CONFIG_PROP_PENDINGREQUESTID_DIGIST_SECRET, "Can NOT generate HMAC key"}, + e); + + } + + log.info(this.getClass().getName() + " initialized with digistAlg: {} and maxLifeTime: {}", + digistAlgorithm, maxPendingRequestIdLifeTime); + + } + + private String buildInternalToken(final String internalPendingReqId, final DateTime now) { + return new StringBuilder().append(TOKEN_TEXTUAL_DATE_FORMAT.print(now)).append(TOKEN_SEPARATOR) + .append(internalPendingReqId).toString(); + } + + private byte[] calculateHmac(final String toSign) throws EaafIllegalStateException { + try { + final Mac mac = Mac.getInstance(digistAlgorithm); + mac.init(key); + return mac.doFinal(toSign.getBytes("UTF-8")); + + } catch (UnsupportedEncodingException | NoSuchAlgorithmException | InvalidKeyException e) { + log.error("Can NOT generate secure pendingRequestId", e); + throw new EaafIllegalStateException( + new Object[] {"Can NOT caluclate digist for secure pendingRequestId"}, e); + + } + + } } diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/ServletUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/ServletUtils.java index 38e873e2..0d16e9cd 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/ServletUtils.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/ServletUtils.java @@ -1,43 +1,41 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. + */ package at.gv.egiz.eaaf.core.impl.utils; import javax.servlet.http.HttpServletRequest; public class ServletUtils { - - - public static String getBaseUrl( HttpServletRequest request ) { - if ( ( request.getServerPort() == 80 ) || - ( request.getServerPort() == 443 ) ) - return request.getScheme() + "://" + - request.getServerName() + - request.getContextPath(); - else - return request.getScheme() + "://" + - request.getServerName() + ":" + request.getServerPort() + - request.getContextPath(); - } - + + /** + * Get Context URL from http request. + * + * @param request http Request + * @return Context URL + */ + public static String getBaseUrl(final HttpServletRequest request) { + if ((request.getServerPort() == 80) || (request.getServerPort() == 443)) { + return request.getScheme() + "://" + request.getServerName() + request.getContextPath(); + } else { + return request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + + request.getContextPath(); + } + } + } diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SimplePendingRequestIdGenerationStrategy.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SimplePendingRequestIdGenerationStrategy.java index 6b8fe9b7..049f7175 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SimplePendingRequestIdGenerationStrategy.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/SimplePendingRequestIdGenerationStrategy.java @@ -1,38 +1,42 @@ package at.gv.egiz.eaaf.core.impl.utils; -import org.apache.commons.lang3.StringUtils; - import at.gv.egiz.eaaf.core.api.utils.IPendingRequestIdGenerationStrategy; import at.gv.egiz.eaaf.core.exceptions.PendingReqIdValidationException; +import org.apache.commons.lang3.StringUtils; /** - * Simple pendingRequestId generation strategy that facilitates no extended validation - * + * Simple pendingRequestId generation strategy that facilitates no extended validation. + * * @author tlenz * */ -public class SimplePendingRequestIdGenerationStrategy implements IPendingRequestIdGenerationStrategy { - - @Override - public String generateExternalPendingRequestId() { - return Random.nextLongRandom(); - - } - - @Override - public String validateAndGetPendingRequestId(String pendingReqId) throws PendingReqIdValidationException { - return getPendingRequestIdWithOutChecks(pendingReqId); - - } - - @Override - public String getPendingRequestIdWithOutChecks(String externalPendingReqId) throws PendingReqIdValidationException { - if (StringUtils.isEmpty(externalPendingReqId)) - throw new PendingReqIdValidationException(externalPendingReqId, "PendingRequestId is empty or null"); - - - - return externalPendingReqId; - } +public class SimplePendingRequestIdGenerationStrategy + implements IPendingRequestIdGenerationStrategy { + + @Override + public String generateExternalPendingRequestId() { + return Random.nextLongRandom(); + + } + + @Override + public String validateAndGetPendingRequestId(final String pendingReqId) + throws PendingReqIdValidationException { + return getPendingRequestIdWithOutChecks(pendingReqId); + + } + + @Override + public String getPendingRequestIdWithOutChecks(final String externalPendingReqId) + throws PendingReqIdValidationException { + if (StringUtils.isEmpty(externalPendingReqId)) { + throw new PendingReqIdValidationException(externalPendingReqId, + "PendingRequestId is empty or null"); + } + + + + return externalPendingReqId; + } } diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/StreamUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/StreamUtils.java index 530da777..cc784870 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/StreamUtils.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/StreamUtils.java @@ -1,29 +1,22 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. + */ + package at.gv.egiz.eaaf.core.impl.utils; @@ -32,38 +25,37 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.PrintStream; /** * Utility methods for streams. - * + * * @author Patrick Peck * @version $Id$ */ public class StreamUtils { - + /** * Compare the contents of two InputStreams. - * + * * @param is1 The 1st InputStream to compare. * @param is2 The 2nd InputStream to compare. - * @return boolean true, if both streams contain the exactly the - * same content, false otherwise. + * @return boolean true, if both streams contain the exactly the same content, + * false otherwise. * @throws IOException An error occurred reading one of the streams. */ - public static boolean compareStreams(InputStream is1, InputStream is2) - throws IOException { - - byte[] buf1 = new byte[256]; - byte[] buf2 = new byte[256]; + public static boolean compareStreams(final InputStream is1, final InputStream is2) + throws IOException { + + final byte[] buf1 = new byte[256]; + final byte[] buf2 = new byte[256]; int length1; int length2; - + try { while (true) { length1 = is1.read(buf1); length2 = is2.read(buf2); - + if (length1 != length2) { return false; } @@ -74,128 +66,125 @@ public class StreamUtils { return false; } } - } catch (IOException e) { + } catch (final IOException e) { throw e; } finally { // close both streams try { is1.close(); is2.close(); - } catch (IOException e) { - // ignore this + } catch (final IOException e) { + e.printStackTrace(); + } } } - + /** * Compare two byte arrays, up to a given maximum length. - * + * * @param b1 1st byte array to compare. * @param b2 2nd byte array to compare. * @param length The maximum number of bytes to compare. - * @return true, if the byte arrays are equal, false - * otherwise. + * @return true, if the byte arrays are equal, false otherwise. */ - private static boolean compareBytes(byte[] b1, byte[] b2, int length) { + private static boolean compareBytes(final byte[] b1, final byte[] b2, final int length) { if (b1.length != b2.length) { return false; } - + for (int i = 0; i < b1.length && i < length; i++) { if (b1[i] != b2[i]) { return false; } } - + return true; } /** * Reads a byte array from a stream. + * * @param in The InputStream to read. * @return The bytes contained in the given InputStream. * @throws IOException on any exception thrown */ - public static byte[] readStream(InputStream in) throws IOException { + public static byte[] readStream(final InputStream in) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); copyStream(in, out, null); - - /* - ByteArrayOutputStream out = new ByteArrayOutputStream(); - int b; - while ((b = in.read()) >= 0) - out.write(b); - - */ + + /* + * ByteArrayOutputStream out = new ByteArrayOutputStream(); int b; while ((b = in.read()) >= 0) + * out.write(b); + * + */ in.close(); return out.toByteArray(); } /** * Reads a String from a stream, using given encoding. + * * @param in The InputStream to read. - * @param encoding The character encoding to use for converting the bytes - * of the InputStream into a String. - * @return The content of the given InputStream converted into - * a String. + * @param encoding The character encoding to use for converting the bytes of the + * InputStream into a String. + * @return The content of the given InputStream converted into a String. * @throws IOException on any exception thrown */ - public static String readStream(InputStream in, String encoding) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); + public static String readStream(final InputStream in, final String encoding) throws IOException { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); copyStream(in, out, null); /* - ByteArrayOutputStream out = new ByteArrayOutputStream(); - int b; - while ((b = in.read()) >= 0) - out.write(b); - */ + * ByteArrayOutputStream out = new ByteArrayOutputStream(); int b; while ((b = in.read()) >= 0) + * out.write(b); + */ in.close(); return out.toString(encoding); } - + /** - * Reads all data (until EOF is reached) from the given source to the - * destination stream. If the destination stream is null, all data is dropped. - * It uses the given buffer to read data and forward it. If the buffer is - * null, this method allocates a buffer. + * Reads all data (until EOF is reached) from the given source to the destination stream. If the + * destination stream is null, all data is dropped. It uses the given buffer to read data and + * forward it. If the buffer is null, this method allocates a buffer. * * @param source The stream providing the data. - * @param destination The stream that takes the data. If this is null, all - * data from source will be read and discarded. - * @param buffer The buffer to use for forwarding. If it is null, the method - * allocates a buffer. - * @exception IOException If reading from the source or writing to the - * destination fails. + * @param destination The stream that takes the data. If this is null, all data from source will + * be read and discarded. + * @param buffer The buffer to use for forwarding. If it is null, the method allocates a buffer. + * @exception IOException If reading from the source or writing to the destination fails. */ - private static void copyStream(InputStream source, OutputStream destination, byte[] buffer) throws IOException { + private static void copyStream(final InputStream source, final OutputStream destination, + byte[] buffer) throws IOException { if (source == null) { throw new NullPointerException("Argument \"source\" must not be null."); } if (buffer == null) { buffer = new byte[8192]; } - + if (destination != null) { int bytesRead; while ((bytesRead = source.read(buffer)) >= 0) { destination.write(buffer, 0, bytesRead); } } else { - while (source.read(buffer) >= 0); - } - } - - /** - * Gets the stack trace of the Throwable passed in as a string. - * @param t The Throwable. - * @return a String representing the stack trace of the Throwable. - */ - public static String getStackTraceAsString(Throwable t) - { - ByteArrayOutputStream stackTraceBIS = new ByteArrayOutputStream(); - t.printStackTrace(new PrintStream(stackTraceBIS)); - return new String(stackTraceBIS.toByteArray()); + while (source.read(buffer) >= 0) { + + } + } } + + // /** + // * Gets the stack trace of the Throwable passed in as a string. + // * + // * @param t The Throwable. + // * @return a String representing the stack trace of the Throwable. + // */ + // public static String getStackTraceAsString(final Throwable t) { + // final ByteArrayOutputStream stackTraceBis = new ByteArrayOutputStream(); + // t.printStackTrace(new PrintStream(stackTraceBis)); + // return new String(stackTraceBis.toByteArray()); + // } } diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIDUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIDUtils.java deleted file mode 100644 index 2e016848..00000000 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIDUtils.java +++ /dev/null @@ -1,101 +0,0 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * https://joinup.ec.europa.eu/news/understanding-eupl-v12 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -package at.gv.egiz.eaaf.core.impl.utils; - - -import at.gv.egiz.eaaf.core.api.IRequest; - -/** - * @author tlenz - * - */ -public class TransactionIDUtils { - - //MDC variables for logging - public static final String MDC_TRANSACTION_ID = "transactionId"; - public static final String MDC_SESSION_ID = "sessionId"; - public static final String MDC_SERVICEPROVIDER_ID = "oaId"; - - /** - * Set all MDC variables from pending request to this threat context
- * These includes SessionID, TransactionID, and unique service-provider identifier - * - * @param pendingRequest - */ - public static void setAllLoggingVariables(IRequest pendingRequest) { - setTransactionId(pendingRequest.getUniqueTransactionIdentifier()); - setSessionId(pendingRequest.getUniqueSessionIdentifier()); - setServiceProviderId(pendingRequest.getServiceProviderConfiguration().getUniqueIdentifier()); - - } - - /** - * Remove all MDC variables from this threat context - * - */ - public static void removeAllLoggingVariables() { - removeSessionId(); - removeTransactionId(); - removeServiceProviderId(); - - } - - - public static void setServiceProviderId(String oaUniqueId) { - org.slf4j.MDC.put(MDC_SERVICEPROVIDER_ID, oaUniqueId); - - } - - public static void removeServiceProviderId() { - org.slf4j.MDC.remove(MDC_SERVICEPROVIDER_ID); - - } - - public static void setTransactionId(String pendingRequestID) { - org.slf4j.MDC.put(MDC_TRANSACTION_ID, - "TID-" + pendingRequestID); - - } - - public static void removeTransactionId() { - org.slf4j.MDC.remove(MDC_TRANSACTION_ID); - - } - - public static void setSessionId(String uniqueSessionId) { - org.slf4j.MDC.put(MDC_SESSION_ID, - "SID-" + uniqueSessionId); - - } - - public static void removeSessionId() { - org.slf4j.MDC.remove(MDC_SESSION_ID); - - } - - -} diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIdUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIdUtils.java new file mode 100644 index 00000000..3875e587 --- /dev/null +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/TransactionIdUtils.java @@ -0,0 +1,94 @@ +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.gv.egiz.eaaf.core.impl.utils; + + +import at.gv.egiz.eaaf.core.api.IRequest; + +/** + * Transaction Identifier Utils. + * + * @author tlenz + * + */ +public class TransactionIdUtils { + + // MDC variables for logging + public static final String MDC_TRANSACTION_ID = "transactionId"; + public static final String MDC_SESSION_ID = "sessionId"; + public static final String MDC_SERVICEPROVIDER_ID = "oaId"; + + /** + * Set all MDC variables from pending request to this threat context.
+ * These includes SessionID, TransactionID, and unique service-provider identifier + * + * @param pendingRequest Http request object + */ + public static void setAllLoggingVariables(final IRequest pendingRequest) { + setTransactionId(pendingRequest.getUniqueTransactionIdentifier()); + setSessionId(pendingRequest.getUniqueSessionIdentifier()); + setServiceProviderId(pendingRequest.getServiceProviderConfiguration().getUniqueIdentifier()); + + } + + /** + * Remove all MDC variables from this threat context. + * + */ + public static void removeAllLoggingVariables() { + removeSessionId(); + removeTransactionId(); + removeServiceProviderId(); + + } + + + public static void setServiceProviderId(final String oaUniqueId) { + org.slf4j.MDC.put(MDC_SERVICEPROVIDER_ID, oaUniqueId); + + } + + public static void removeServiceProviderId() { + org.slf4j.MDC.remove(MDC_SERVICEPROVIDER_ID); + + } + + public static void setTransactionId(final String pendingRequestID) { + org.slf4j.MDC.put(MDC_TRANSACTION_ID, "TID-" + pendingRequestID); + + } + + public static void removeTransactionId() { + org.slf4j.MDC.remove(MDC_TRANSACTION_ID); + + } + + public static void setSessionId(final String uniqueSessionId) { + org.slf4j.MDC.put(MDC_SESSION_ID, "SID-" + uniqueSessionId); + + } + + public static void removeSessionId() { + org.slf4j.MDC.remove(MDC_SESSION_ID); + + } + + +} diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/X509Utils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/X509Utils.java index b3fb42c4..00a31a13 100644 --- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/X509Utils.java +++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/X509Utils.java @@ -7,56 +7,45 @@ import javax.security.auth.x500.X500Principal; public class X509Utils { - /** - * Sorts the Certificate Chain by IssuerDN and SubjectDN. The [0]-Element should be the Hostname, - * the last Element should be the Root Certificate. - * - * @param certs - * The first element must be the correct one. - * @return sorted Certificate Chain - */ - public static List sortCertificates( - List certs) - { - int length = certs.size(); - if (certs.size() <= 1) - { - return certs; - } + /** + * Sorts the Certificate Chain by IssuerDN and SubjectDN. The [0]-Element should be the Hostname, + * the last Element should be the Root Certificate. + * + * @param certs The first element must be the correct one. + * @return sorted Certificate Chain + */ + public static List sortCertificates(final List certs) { + final int length = certs.size(); + if (certs.size() <= 1) { + return certs; + } - for (X509Certificate cert : certs) - { - if (cert == null) - { - throw new NullPointerException(); - } - } + for (final X509Certificate cert : certs) { + if (cert == null) { + throw new NullPointerException(); + } + } - for (int i = 0; i < length; i++) - { - boolean found = false; - X500Principal issuer = certs.get(i).getIssuerX500Principal(); - for (int j = i + 1; j < length; j++) - { - X500Principal subject = certs.get(j).getSubjectX500Principal(); - if (issuer.equals(subject)) - { - // sorting necessary? - if (i + 1 != j) - { - X509Certificate tmp = certs.get(i + 1); - certs.set(i + 1, certs.get(j)); - certs.set(j, tmp); - } - found = true; - } - } - if (!found) - { - break; - } - } + for (int i = 0; i < length; i++) { + boolean found = false; + final X500Principal issuer = certs.get(i).getIssuerX500Principal(); + for (int j = i + 1; j < length; j++) { + final X500Principal subject = certs.get(j).getSubjectX500Principal(); + if (issuer.equals(subject)) { + // sorting necessary? + if (i + 1 != j) { + final X509Certificate tmp = certs.get(i + 1); + certs.set(i + 1, certs.get(j)); + certs.set(j, tmp); + } + found = true; + } + } + if (!found) { + break; + } + } - return certs; - } + return certs; + } } diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/logging/JUnitTestStatusMessenger.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/logging/JUnitTestStatusMessenger.java index 5cdd404c..be5d95b1 100644 --- a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/logging/JUnitTestStatusMessenger.java +++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/logging/JUnitTestStatusMessenger.java @@ -3,54 +3,59 @@ package at.gv.egiz.eaaf.core.impl.logging; import java.text.MessageFormat; import java.util.HashMap; import java.util.Map; - import at.gv.egiz.eaaf.core.api.IStatusMessenger; public class JUnitTestStatusMessenger implements IStatusMessenger { - private final Map msgStore = new HashMap<>(); - - @Override - public String getMessage(String messageId, Object[] parameters) { - final String msg = getMessageWithoutDefault(messageId, parameters); - if (msg != null) { - return msg; - - } else { - return MessageFormat.format(messageId, parameters); - - } - - } - - @Override - public String getMessageWithoutDefault(String messageId, Object[] parameters) { - if (messageId != null) { - if (msgStore.containsKey(messageId)) { - return MessageFormat.format(msgStore.get(messageId), parameters); - - } - } - - return null; - } - - @Override - public String getResponseErrorCode(Throwable throwable) { - return null; - } - - @Override - public String mapInternalErrorToExternalError(String intErrorCode) { - return null; - } - - public void addMsg(String msgCode, String msg) { - if (!msgStore.containsKey(msgCode)) { - msgStore.put(msgCode, msg); - - } - - } - + private final Map msgStore = new HashMap<>(); + + @Override + public String getMessage(final String messageId, final Object[] parameters) { + final String msg = getMessageWithoutDefault(messageId, parameters); + if (msg != null) { + return msg; + + } else { + return MessageFormat.format(messageId, parameters); + + } + + } + + @Override + public String getMessageWithoutDefault(final String messageId, final Object[] parameters) { + if (messageId != null) { + if (msgStore.containsKey(messageId)) { + return MessageFormat.format(msgStore.get(messageId), parameters); + + } + } + + return null; + } + + @Override + public String getResponseErrorCode(final Throwable throwable) { + return null; + } + + @Override + public String mapInternalErrorToExternalError(final String intErrorCode) { + return null; + } + + /** + * Add a message into Message-Store. + * + * @param msgCode message-code + * @param msg message + */ + public void addMsg(final String msgCode, final String msg) { + if (!msgStore.containsKey(msgCode)) { + msgStore.put(msgCode, msg); + + } + + } + } diff --git a/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/KeyValueUtilsTest.java b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/KeyValueUtilsTest.java new file mode 100644 index 00000000..258c3210 --- /dev/null +++ b/eaaf_core_utils/src/test/java/at/gv/egiz/eaaf/core/impl/utils/test/KeyValueUtilsTest.java @@ -0,0 +1,446 @@ +package at.gv.egiz.eaaf.core.impl.utils.test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import at.gv.egiz.eaaf.core.impl.utils.KeyValueUtils; +import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; +import com.google.common.collect.Sets; + +@RunWith(BlockJUnit4ClassRunner.class) +public class KeyValueUtilsTest { + + @Test + public void getFirstChildTest_1() { + final String prefix = RandomStringUtils.randomAlphabetic(4) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(6) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(5); + final String child = RandomStringUtils.randomAlphabetic(2); + final String key = prefix + KeyValueUtils.KEY_DELIMITER + child + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(4); + final String resut = KeyValueUtils.getFirstChildAfterPrefix(key, prefix); + Assert.assertEquals("First child not match", child, resut); + + } + + @Test + public void getFirstChildTest_2() { + final String prefix = RandomStringUtils.randomAlphabetic(4) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(6) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(5); + final String child = RandomStringUtils.randomAlphabetic(2); + final String key = prefix + KeyValueUtils.KEY_DELIMITER + child; + final String resut = KeyValueUtils.getFirstChildAfterPrefix(key, prefix); + Assert.assertEquals("First child not match", child, resut); + + } + + @Test + public void getFirstChildTest_3() { + final String prefix = RandomStringUtils.randomAlphabetic(4) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(6) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(5); + final String child = RandomStringUtils.randomAlphabetic(2); + final String key = prefix + KeyValueUtils.KEY_DELIMITER + child; + final String resut = KeyValueUtils.getFirstChildAfterPrefix(key, key); + Assert.assertNull("First child not null", resut); + + } + + @Test + public void getFirstChildTest_4() { + final String prefix = RandomStringUtils.randomAlphabetic(4) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(6) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(5); + final String child = RandomStringUtils.randomAlphabetic(2); + final String key = prefix + KeyValueUtils.KEY_DELIMITER + child; + final String resut = KeyValueUtils.getFirstChildAfterPrefix( + RandomStringUtils.randomAlphabetic(4) + KeyValueUtils.KEY_DELIMITER + key, key); + Assert.assertNull("First child not null", resut); + + } + + @Test + public void getFirstChildTest_5() { + final String prefix = RandomStringUtils.randomAlphabetic(4) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(6) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(5); + final String child = RandomStringUtils.randomAlphabetic(2); + final String key = child + KeyValueUtils.KEY_DELIMITER + prefix; + final String resut = KeyValueUtils.getFirstChildAfterPrefix(key, null); + Assert.assertEquals("First child not match", child, resut); + + } + + @Test + public void getFirstChildTest_6() { + final String prefix = RandomStringUtils.randomAlphabetic(4) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(6) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(5); + final String child = RandomStringUtils.randomAlphabetic(2); + final String key = prefix + KeyValueUtils.KEY_DELIMITER + child; + final String resut = KeyValueUtils.getFirstChildAfterPrefix(key, key); + Assert.assertNull("First child not null", resut); + + } + + @Test + public void getPrefixFromKey_1() { + final String prefix = RandomStringUtils.randomAlphabetic(4) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(6) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(5); + final String child = RandomStringUtils.randomAlphabetic(2); + final String key = prefix + KeyValueUtils.KEY_DELIMITER + child; + final String resut = KeyValueUtils.getPrefixFromKey(key, child); + Assert.assertEquals("Prefix not match", prefix, resut); + + } + + @Test + public void getPrefixFromKey_2() { + final String child = RandomStringUtils.randomAlphabetic(2); + final String resut = KeyValueUtils.getPrefixFromKey(null, child); + Assert.assertNull("Prefix not null", resut); + + } + + @Test + public void getPrefixFromKey_3() { + final String prefix = RandomStringUtils.randomAlphabetic(4) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(6) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(5); + final String key = prefix + KeyValueUtils.KEY_DELIMITER + RandomStringUtils.randomAlphabetic(4); + final String resut = KeyValueUtils.getPrefixFromKey(key, RandomStringUtils.randomAlphabetic(5)); + Assert.assertNull("Prefix not null", resut); + + } + + @Test + public void getPrefixFromKey_4() { + final String prefix = RandomStringUtils.randomAlphabetic(4) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(6) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(5); + final String child = KeyValueUtils.KEY_DELIMITER + RandomStringUtils.randomAlphabetic(2); + final String key = prefix + child; + final String resut = KeyValueUtils.getPrefixFromKey(key, child); + Assert.assertEquals("Prefix not match", prefix, resut); + + } + + @Test + public void getPrefixFromKey_5() { + final String key = RandomStringUtils.randomAlphabetic(4) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(6) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(5); + final String resut = KeyValueUtils.getPrefixFromKey(key, null); + Assert.assertNull("Prefix not null", resut); + + } + + @Test + public void getRemovePrefixesFromKeys_1() { + final String testPrefix = RandomStringUtils.randomAlphabetic(4) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(6) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(5); + final Map testMap = generateTestMap(testPrefix, 5, 5); + + final Map result = KeyValueUtils.removePrefixFromKeys(testMap, testPrefix); + Assert.assertNotNull("Result is null", result); + Assert.assertFalse("Result is empty", result.isEmpty()); + Assert.assertEquals("Result size not match", 5, result.size()); + final Iterator> it = result.entrySet().iterator(); + while (it.hasNext()) { + final Entry next = it.next(); + Assert.assertNotNull("Key is null", next.getKey()); + Assert.assertNotNull("Value is null", next.getValue()); + Assert.assertTrue("Key is null", testMap.containsKey(testPrefix + "." + next.getKey())); + Assert.assertEquals("Value not match", testMap.get(testPrefix + "." + next.getKey()), + next.getValue()); + + } + + } + + @Test + public void getSubSetWithPrefixTest_1() { + final String testPrefix = RandomStringUtils.randomAlphabetic(4) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(6) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(5); + final Map testMap = generateTestMap(testPrefix, 5, 5); + + final Map result = KeyValueUtils.getSubSetWithPrefix(testMap, testPrefix); + Assert.assertNotNull("Result is null", result); + Assert.assertFalse("Result is empty", result.isEmpty()); + Assert.assertEquals("Result size not match", 5, result.size()); + final Iterator> it = result.entrySet().iterator(); + while (it.hasNext()) { + final Entry next = it.next(); + Assert.assertNotNull("Key is null", next.getKey()); + Assert.assertNotNull("Value is null", next.getValue()); + Assert.assertTrue("Key is null", testMap.containsKey(testPrefix + "." + next.getKey())); + Assert.assertEquals("Value not match", testMap.get(testPrefix + "." + next.getKey()), + next.getValue()); + + } + + } + + @Test + public void makeKeysAbsolutTest_1() { + final String absTestPrefixtestPrefix = RandomStringUtils.randomAlphabetic(4) + + KeyValueUtils.KEY_DELIMITER + RandomStringUtils.randomAlphabetic(6) + + KeyValueUtils.KEY_DELIMITER + RandomStringUtils.randomAlphabetic(5); + final String prefix = absTestPrefixtestPrefix + "." + RandomStringUtils.randomAlphabetic(4); + final Map testMap = generateTestMap(prefix, 5, 5); + final Map result = + KeyValueUtils.makeKeysAbsolut(testMap, absTestPrefixtestPrefix, prefix); + + Assert.assertNotNull("Result is null", result); + Assert.assertFalse("Result is empty", result.isEmpty()); + Assert.assertEquals("Result size not match", 10, result.size()); + final Iterator> it = result.entrySet().iterator(); + while (it.hasNext()) { + final Entry next = it.next(); + Assert.assertNotNull("Key is null", next.getKey()); + Assert.assertNotNull("Value is null", next.getValue()); + if (testMap.containsKey(next.getKey())) { + Assert.assertEquals("Value not match", testMap.get(next.getKey()), next.getValue()); + } else { + Assert.assertTrue("Key not found", + testMap.containsKey(next.getKey().substring(absTestPrefixtestPrefix.length() + 1))); + Assert.assertEquals("Value not match", + testMap.get(next.getKey().substring(absTestPrefixtestPrefix.length() + 1)), + next.getValue()); + } + } + } + + @Test + public void getParentKeyTest_1() { + final String testPrefix = RandomStringUtils.randomAlphabetic(4) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(6) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(5); + final String result = + KeyValueUtils.getParentKey(testPrefix + "." + RandomStringUtils.randomAlphabetic(5)); + Assert.assertNotNull("Result is null", result); + Assert.assertEquals("Parent not match", testPrefix, result); + + } + + @Test + public void getParentKeyTest_2() { + final String result = KeyValueUtils.getParentKey(RandomStringUtils.randomAlphabetic(5)); + Assert.assertNotNull("Result is null", result); + Assert.assertTrue("Result not empty", result.isEmpty()); + + } + + @Test + public void findNextFreeListCoutnerTest_1() { + final String testPrefix = RandomStringUtils.randomAlphabetic(4) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(6) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(5); + final java.util.List propList = new ArrayList<>(); + propList.add(testPrefix + ".1"); + propList.add(testPrefix + ".2"); + propList.add(testPrefix + ".0"); + propList.add(testPrefix + ".4"); + propList.add(testPrefix + ".3"); + + final int result = KeyValueUtils.findNextFreeListCounter(Sets.newHashSet(propList), testPrefix); + Assert.assertEquals("Next free element not fount", 5, result); + + } + + @Test + public void findNextFreeListCoutnerTest_2() { + final String testPrefix = RandomStringUtils.randomAlphabetic(4) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(6) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(5); + final java.util.List propList = new ArrayList<>(); + propList.add(testPrefix + ".1"); + propList.add(testPrefix + ".5"); + propList.add(testPrefix + ".0"); + propList.add(testPrefix + ".4"); + propList.add(testPrefix + ".3"); + + final int result = KeyValueUtils.findNextFreeListCounter(Sets.newHashSet(propList), testPrefix); + Assert.assertEquals("Next free element not fount", 6, result); + + } + + @Test + public void findNextFreeListCoutnerTest_3() { + final String testPrefix = RandomStringUtils.randomAlphabetic(4) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(6) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(5); + final java.util.List propList = new ArrayList<>(); + + final int result = KeyValueUtils.findNextFreeListCounter(Sets.newHashSet(propList), testPrefix); + Assert.assertEquals("Next free element not fount", 0, result); + + } + + @Test + public void findNextFreeListCoutnerTest_4() { + final String testPrefix = RandomStringUtils.randomAlphabetic(4) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(6) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(5); + final java.util.List propList = new ArrayList<>(); + + final int result = + KeyValueUtils.findNextFreeListCounter(propList.stream().toArray(String[]::new), testPrefix); + Assert.assertEquals("Next free element not fount", 0, result); + + } + + @Test + public void normalizeCsvValueStringTest_1() { + final String csv1 = RandomStringUtils.randomAlphanumeric(5); + final String csv2 = RandomStringUtils.randomAlphanumeric(5); + final String csv3 = RandomStringUtils.randomAlphanumeric(5); + final String csv4 = RandomStringUtils.randomAlphanumeric(5); + final String testValue = " " + csv1 + " ," + csv2 + "," + csv3 + "\n," + csv4 + " "; + + final String result = KeyValueUtils.normalizeCsvValueString(testValue); + + Assert.assertNotNull("Result is null", result); + Assert.assertFalse("Result is empty", result.isEmpty()); + final String[] check = result.split(","); + Assert.assertEquals("Result size wrong", 4, check.length); + Assert.assertEquals("Result 1 wrong", csv1, check[0]); + Assert.assertEquals("Result 2 wrong", csv2, check[1]); + Assert.assertEquals("Result 3 wrong", csv3, check[2]); + Assert.assertEquals("Result 4 wrong", csv4, check[3]); + + } + + @Test + public void isCsvValueStringTest_1() { + final String csv1 = RandomStringUtils.randomAlphanumeric(5); + final String csv2 = RandomStringUtils.randomAlphanumeric(5); + final String csv3 = RandomStringUtils.randomAlphanumeric(5); + final String csv4 = RandomStringUtils.randomAlphanumeric(5); + final String testValue = " " + csv1 + " ," + csv2 + "," + csv3 + "\n," + csv4 + " "; + final boolean result = KeyValueUtils.isCsvValueString(testValue); + Assert.assertTrue("CSV value not detected", result); + + } + + @Test + public void isCsvValueStringTest_2() { + final String csv1 = RandomStringUtils.randomAlphanumeric(5); + final String testValue = " " + csv1 + " ,"; + final boolean result = KeyValueUtils.isCsvValueString(testValue); + Assert.assertFalse("CSV value not detected", result); + + } + + @Test + public void isCsvValueStringTest_3() { + final String csv1 = RandomStringUtils.randomAlphanumeric(5); + final String testValue = " " + csv1; + final boolean result = KeyValueUtils.isCsvValueString(testValue); + Assert.assertFalse("CSV value not detected", result); + + } + + @Test + public void getListOfCsvValuesTest_1() { + final String csv1 = RandomStringUtils.randomAlphanumeric(5); + final String csv2 = RandomStringUtils.randomAlphanumeric(5); + final String csv3 = RandomStringUtils.randomAlphanumeric(5); + final String csv4 = RandomStringUtils.randomAlphanumeric(5); + final String testValue = " " + csv1 + " ," + csv2 + "," + csv3 + "\n," + csv4 + " "; + + final List result = KeyValueUtils.getListOfCsvValues(testValue); + + Assert.assertNotNull("Result is null", result); + Assert.assertFalse("Result is empty", result.isEmpty()); + Assert.assertEquals("Result size wrong", 4, result.size()); + Assert.assertEquals("Result 1 wrong", csv1, result.get(0)); + Assert.assertEquals("Result 2 wrong", csv2, result.get(1)); + Assert.assertEquals("Result 3 wrong", csv3, result.get(2)); + Assert.assertEquals("Result 4 wrong", csv4, result.get(3)); + + } + + @Test + public void convertListToMapTest_1() { + final java.util.List propList = new ArrayList<>(); + final String prefix = RandomStringUtils.randomAlphabetic(4) + "."; + final String key1 = RandomStringUtils.randomAlphabetic(5); + final String value1 = RandomStringUtils.randomAlphanumeric(10); + final String key2 = RandomStringUtils.randomAlphabetic(5); + final String value2 = RandomStringUtils.randomAlphanumeric(10); + final String key3 = RandomStringUtils.randomAlphabetic(5); + final String value3 = RandomStringUtils.randomAlphanumeric(10); + final String key4 = RandomStringUtils.randomAlphabetic(5); + final String value4 = RandomStringUtils.randomAlphanumeric(10); + final String key5 = RandomStringUtils.randomAlphabetic(5); + final String value5 = RandomStringUtils.randomAlphanumeric(10); + final String key6 = RandomStringUtils.randomAlphabetic(5); + final String value6 = "=" + RandomStringUtils.randomAlphanumeric(10); + + propList.add(prefix + key1 + "=" + value1); + propList.add(prefix + key2 + "=" + value2); + propList.add(prefix + key3 + "=" + value3); + propList.add(prefix + key4 + "=" + value4); + propList.add(prefix + key5 + "+" + value5); + propList.add(prefix + key6 + "=" + value6); + + final Map result = KeyValueUtils.convertListToMap(propList); + Assert.assertNotNull("Result is null", result); + Assert.assertFalse("Result is empty", result.isEmpty()); + Assert.assertEquals("Result size not match", 5, result.size()); + + Assert.assertTrue("Key1 not found", result.containsKey(prefix + key1)); + Assert.assertEquals("Value1 not found", value1, result.get(prefix + key1)); + Assert.assertTrue("Key2 not found", result.containsKey(prefix + key2)); + Assert.assertEquals("Value2 not found", value2, result.get(prefix + key2)); + Assert.assertTrue("Key3 not found", result.containsKey(prefix + key3)); + Assert.assertEquals("Value3 not found", value3, result.get(prefix + key3)); + Assert.assertTrue("Key4 not found", result.containsKey(prefix + key4)); + Assert.assertEquals("Value4 not found", value4, result.get(prefix + key4)); + + } + + @Test + public void convertListToMapTest_2() { + final java.util.List propList = new ArrayList<>(); + + final Map result = KeyValueUtils.convertListToMap(propList); + Assert.assertNotNull("Result is null", result); + Assert.assertTrue("Result is not empty", result.isEmpty()); + + } + + private Map generateTestMap(final String testPrefix, final int entriesWithPrefix, + final int entriesWithoutPrefix) { + final Map result = new HashMap<>(); + for (int i = 0; i < entriesWithPrefix; i++) { + result.put(testPrefix + KeyValueUtils.KEY_DELIMITER + RandomStringUtils.randomAlphabetic(5), + RandomStringUtils.randomAlphabetic(5)); + } + + final String key = RandomStringUtils.randomAlphabetic(4) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(6) + KeyValueUtils.KEY_DELIMITER + + RandomStringUtils.randomAlphabetic(5); + for (int i = 0; i < entriesWithoutPrefix; i++) { + result.put(key + KeyValueUtils.KEY_DELIMITER + RandomStringUtils.randomAlphabetic(5), + RandomStringUtils.randomAlphabetic(5)); + } + + return result; + + } + + +} -- cgit v1.2.3