summaryrefslogtreecommitdiff
path: root/eaaf_core_utils/src/main
diff options
context:
space:
mode:
authorThomas <>2024-08-29 09:52:25 +0200
committerThomas <>2024-08-29 09:52:25 +0200
commit61c0fbc5eb9d24267d4ca24cdebe4566e959bd02 (patch)
tree5eb5f8da91042bf1361f7527093b25b2352d4256 /eaaf_core_utils/src/main
parenta6b70202f08ca2d612bd8b33ad1f51ee0fc26333 (diff)
downloadEAAF-Components-61c0fbc5eb9d24267d4ca24cdebe4566e959bd02.tar.gz
EAAF-Components-61c0fbc5eb9d24267d4ca24cdebe4566e959bd02.tar.bz2
EAAF-Components-61c0fbc5eb9d24267d4ca24cdebe4566e959bd02.zip
feat(utils): add RFC7636 (Outh2 PKCE) implementation
Diffstat (limited to 'eaaf_core_utils/src/main')
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/Rfc7636Utils.java141
1 files changed, 141 insertions, 0 deletions
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/Rfc7636Utils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/Rfc7636Utils.java
new file mode 100644
index 00000000..b213d932
--- /dev/null
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/Rfc7636Utils.java
@@ -0,0 +1,141 @@
+package at.gv.egiz.eaaf.core.impl.utils;
+
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Base64;
+
+import lombok.Builder;
+import lombok.Getter;
+
+/**
+ * Implements OAuth2 PKCE from RFC7636.
+ */
+public class Rfc7636Utils {
+
+ private SecureRandom random;
+ private static Rfc7636Utils instance = null;
+
+ public static final String PARAM_NAME_VERIFIER = "code_verifier";
+ public static final String PARAM_NAME_CHALLENGE = "code_challenge";
+ public static final String PARAM_NAME_METHOD = "code_challenge_method";
+
+ /**
+ * Get an instance of RFC7636 implementation for PKCE.
+ *
+ * @return {@link Rfc7636Utils}
+ * @throws NoSuchAlgorithmException In case of Secure-Random problems
+ */
+ public static Rfc7636Utils getInstance() throws NoSuchAlgorithmException {
+ if (instance == null) {
+ instance = new Rfc7636Utils();
+
+ }
+ return instance;
+
+ }
+
+ /**
+ * Generates a new pair of PKCE information.
+ *
+ * <p>
+ * Using S256 as method.
+ * </p>
+ *
+ * @return PKCE data that can be directly used
+ * @throws NoSuchAlgorithmException In case of SHA-256 problem
+ */
+ public PkceInfo generate() throws NoSuchAlgorithmException {
+ return generate(Method.S256);
+
+ }
+
+ /**
+ * Generates a new pair of PKCE information.
+ *
+ * @param method Challenge generation method
+ * @return PKCE data that can be directly used
+ * @throws NoSuchAlgorithmException In case of SHA-256 problem
+ */
+ public PkceInfo generate(Method method) throws NoSuchAlgorithmException {
+ String value = generateNewRandomValue();
+ return PkceInfo.builder()
+ .codeMethod(method)
+ .codeVerifier(value)
+ .codeChallenge(calculateChallenge(value, method))
+ .build();
+
+ }
+
+ /**
+ * Verify PKCE information.
+ *
+ * @param input Set of PKCE infos
+ * @return <code>true</code> if infos a valid, otherwise <code>false</code>
+ * @throws NoSuchAlgorithmException In case of SHA-256 problem
+ */
+ public boolean verify(PkceInfo input) throws NoSuchAlgorithmException {
+ return input.codeChallenge.equals(
+ calculateChallenge(input.codeVerifier, input.codeMethod));
+
+ }
+
+ private String calculateChallenge(String value, Method method) throws NoSuchAlgorithmException {
+ if (Method.PLAIN.equals(method)) {
+ return value;
+
+ } else {
+ return encodeB64(MessageDigest.getInstance("SHA-256").digest(
+ value.getBytes(StandardCharsets.US_ASCII)));
+
+ }
+ }
+
+ private String generateNewRandomValue() {
+ byte[] values = new byte[20];
+ random.nextBytes(values);
+ return encodeB64(values);
+
+ }
+
+ private String encodeB64(byte[] input) {
+ return Base64.getUrlEncoder().withoutPadding().encodeToString(input);
+ }
+
+ private Rfc7636Utils() throws NoSuchAlgorithmException {
+ random = SecureRandom.getInstanceStrong();
+
+ }
+
+ public enum Method {
+ S256, PLAIN
+ }
+
+ /**
+ * Holds a fresh pair of PKCE information.
+ *
+ * @author tlenz
+ */
+ @Getter
+ @Builder(toBuilder = true)
+ public static class PkceInfo {
+
+ String codeVerifier;
+
+ String codeChallenge;
+
+ Method codeMethod;
+
+ /**
+ * Get PKCE method as String regarding to RFC7636.
+ *
+ * @return PKCE method
+ */
+ public String getMethod() {
+ return codeMethod.toString();
+
+ }
+
+ }
+}