diff --git a/.gitignore b/.gitignore index c58348b..e2de616 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,11 @@ *.war *.ear +# gradle +!gradle-wrapper.jar +.gradle +/build/ + # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* diff --git a/.travis.yml b/.travis.yml index a7bd7ad..df45553 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,13 @@ sudo: false language: java jdk: - - oraclejdk8 + - oraclejdk9 + +install: +- ./gradlew assemble -x signArchives -i + +script: +- ./gradlew check -x signArchives -i after_failure: chmod +x $TRAVIS_BUILD_DIR/print_surefire_reports.sh; $TRAVIS_BUILD_DIR/print_surefire_reports.sh diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..fd795ca --- /dev/null +++ b/build.gradle @@ -0,0 +1,117 @@ +// Apply the java-library plugin to add support for Java Library +apply plugin: 'java-library' +apply plugin: 'signing' +apply plugin: 'maven' + +group = "org.rootservices" +version = "1.3" +archivesBaseName="jwt" + +description = """JSON Web Tokens""" + +sourceCompatibility = 1.9 +targetCompatibility = 1.9 + +buildscript { + repositories { + mavenCentral() + } +} + +repositories { + mavenCentral() + mavenLocal() +} + +configurations { + deployerJars +} + +ext { + jacksonVersion = '2.8.8' + log4jVersion = '2.11.0' +} + +dependencies { + implementation "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}" + implementation "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}" + implementation "com.fasterxml.jackson.datatype:jackson-datatype-jdk8:${jacksonVersion}" + implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:${jacksonVersion}" + implementation "org.apache.logging.log4j:log4j-api:${log4jVersion}" + implementation "org.apache.logging.log4j:log4j-core:${log4jVersion}" + + testImplementation group: 'junit', name: 'junit', version:'4.12' + testImplementation group: 'org.hamcrest', name: 'hamcrest-all', version:'1.3' + testImplementation group: 'org.mockito', name: 'mockito-all', version:'1.9.5' +} + +task javadocJar(type: Jar) { + classifier = 'javadoc' + from javadoc +} + +task sourcesJar(type: Jar) { + classifier = 'sources' + from sourceSets.main.allSource +} + +artifacts { + archives javadocJar, sourcesJar +} + +signing { + sign configurations.archives +} + +uploadArchives { + repositories { + mavenDeployer { + if(!project.ext.properties.containsKey("ossrhUser")) { + project.ext.ossrhUser = 'wrongUser' + project.ext.ossrhPassword = 'wrongPassword' + } + + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots") { + authentication(userName: ossrhUser, password: ossrhPassword) + } + repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { + authentication(userName: ossrhUser, password: ossrhPassword) + } + pom.project { + groupId 'org.rootservices' + artifactId project.name + version project.version + name project.name + description project.description + packaging 'jar' + url 'https://github.com/RootServices/jwt' + + scm { + connection 'git@github.com:RootServices/jwt.git' + developerConnection 'git@github.com:RootServices/jwt.git' + url 'https://github.com/RootServices/jwt' + } + + licenses { + license { + name 'The MIT License (MIT)' + url 'https://github.com/RootServices/jwt/blob/development/LICENSE' + } + } + + developers { + developer { + id 'tmackenzie' + name 'Tom MacKenzie' + email 'tom@rootservices.org' + } + } + } + } + } +} + +task wrapper(type: Wrapper) { + gradleVersion = '4.6' +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..7a3265e Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..143f0cc --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Thu Mar 22 07:28:59 CDT 2018 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..cccdd3d --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..e95643d --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/pom.xml b/pom.xml deleted file mode 100644 index df18535..0000000 --- a/pom.xml +++ /dev/null @@ -1,172 +0,0 @@ - - - 4.0.0 - - - org.sonatype.oss - oss-parent - 8 - - - JWT - Java implementation of JWT - org.rootservices - jwt - 1.2 - jar - - - UTF-8 - 1.8 - - - - - - com.fasterxml.jackson.core - jackson-core - 2.4.6 - - - - com.fasterxml.jackson.core - jackson-databind - 2.4.6 - - - - com.fasterxml.jackson.datatype - jackson-datatype-jdk8 - 2.5.4 - - - - org.bouncycastle - bcpkix-jdk15on - 1.53 - - - - - junit - junit - 4.11 - test - - - - org.easytesting - fest-assert-core - 2.0M10 - test - - - - org.mockito - mockito-all - 1.9.5 - test - - - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.5 - - methods - 5 - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.1 - - ${java.version} - ${java.version} - true - true - -Xlint:unchecked - - - - org.apache.maven.plugins - maven-source-plugin - 2.4 - - - - jar - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.9.1 - - - attach-javadocs - - jar - - - - - - - - - - sonatype-nexus-snapshots - Sonatype Nexus snapshot repository - https://oss.sonatype.org/content/repositories/snapshots - - - sonatype-nexus-staging - Sonatype Nexus release repository - https://oss.sonatype.org/service/local/staging/deploy/maven2 - - - - - - release-sign-artifacts - - - performRelease - true - - - - - - org.apache.maven.plugins - maven-gpg-plugin - 1.4 - - ${gpg.passphrase} - - - - sign-artifacts - verify - - sign - - - - - - - - - diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..f4f12d9 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,18 @@ +/* + * This settings file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * In a single project build this file can be empty or even removed. + * + * Detailed information about configuring a multi-project build in Gradle can be found + * in the user guide at https://docs.gradle.org/4.1/userguide/multi_project_builds.html + */ + +/* +// To declare projects as part of a multi-project build use the 'include' method +include 'shared' +include 'api' +include 'services:webservice' +*/ + +rootProject.name = 'jwt' diff --git a/src/main/java/org/rootservices/jwt/SecureJwtEncoder.java b/src/main/java/org/rootservices/jwt/SecureJwtEncoder.java deleted file mode 100644 index 018b188..0000000 --- a/src/main/java/org/rootservices/jwt/SecureJwtEncoder.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.rootservices.jwt; - - -import org.rootservices.jwt.entity.jwt.Claims; -import org.rootservices.jwt.entity.jwt.JsonWebToken; -import org.rootservices.jwt.factory.SecureJwtFactory; -import org.rootservices.jwt.factory.UnSecureJwtFactory; -import org.rootservices.jwt.serializer.JWTSerializer; -import org.rootservices.jwt.serializer.exception.JwtToJsonException; - -/** - * Created by tommackenzie on 9/1/16. - */ -public class SecureJwtEncoder { - private SecureJwtFactory secureJwtFactory; - private JWTSerializer jwtSerializer; - - public SecureJwtEncoder(SecureJwtFactory secureJwtFactory, JWTSerializer jwtSerializer) { - this.secureJwtFactory = secureJwtFactory; - this.jwtSerializer = jwtSerializer; - } - - public String encode(Claims claims) throws JwtToJsonException { - - JsonWebToken jsonWebToken = null; - try { - jsonWebToken = secureJwtFactory.makeJwt(claims); - } catch (JwtToJsonException e) { - throw e; - } - - String jwt = null; - try { - jwt = jwtSerializer.jwtToString(jsonWebToken); - } catch (JwtToJsonException e) { - throw e; - } - - return jwt; - } -} diff --git a/src/main/java/org/rootservices/jwt/UnSecureJwtEncoder.java b/src/main/java/org/rootservices/jwt/UnSecureJwtEncoder.java deleted file mode 100644 index 15fafe2..0000000 --- a/src/main/java/org/rootservices/jwt/UnSecureJwtEncoder.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.rootservices.jwt; - -import org.rootservices.jwt.entity.jwt.Claims; -import org.rootservices.jwt.entity.jwt.JsonWebToken; -import org.rootservices.jwt.factory.UnSecureJwtFactory; -import org.rootservices.jwt.serializer.JWTSerializer; -import org.rootservices.jwt.serializer.exception.JwtToJsonException; - -/** - * Created by tommackenzie on 7/12/16. - */ -public class UnSecureJwtEncoder { - private UnSecureJwtFactory unSecureJwtFactory; - private JWTSerializer jwtSerializer; - - public UnSecureJwtEncoder(UnSecureJwtFactory unSecureJwtFactory, JWTSerializer jwtSerializer) { - this.unSecureJwtFactory = unSecureJwtFactory; - this.jwtSerializer = jwtSerializer; - } - - public String encode(Claims claims) { - - JsonWebToken jsonWebToken = unSecureJwtFactory.makeJwt(claims); - - String encodedJwt = null; - try { - encodedJwt = jwtSerializer.jwtToString(jsonWebToken); - } catch (JwtToJsonException e) { - e.printStackTrace(); - } - - return encodedJwt; - } -} diff --git a/src/main/java/org/rootservices/jwt/config/AppFactory.java b/src/main/java/org/rootservices/jwt/config/AppFactory.java deleted file mode 100644 index c2dc7f2..0000000 --- a/src/main/java/org/rootservices/jwt/config/AppFactory.java +++ /dev/null @@ -1,155 +0,0 @@ -package org.rootservices.jwt.config; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.PropertyNamingStrategy; -import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; -import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; -import org.rootservices.jwt.SecureJwtEncoder; -import org.rootservices.jwt.UnSecureJwtEncoder; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidAlgorithmException; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidJsonWebKeyException; -import org.rootservices.jwt.translator.CSRToRSAPublicKey; -import org.rootservices.jwt.translator.PemToRSAKeyPair; -import org.rootservices.jwt.factory.SecureJwtFactory; -import org.rootservices.jwt.factory.UnSecureJwtFactory; -import org.rootservices.jwt.entity.jwk.Key; -import org.rootservices.jwt.entity.jwt.header.Algorithm; -import org.rootservices.jwt.serializer.JWTSerializer; -import org.rootservices.jwt.serializer.Serializer; -import org.rootservices.jwt.signature.signer.factory.hmac.MacFactory; -import org.rootservices.jwt.signature.signer.factory.rsa.PrivateKeySignatureFactory; -import org.rootservices.jwt.signature.signer.factory.rsa.PublicKeySignatureFactory; -import org.rootservices.jwt.signature.verifier.VerifySignature; -import org.rootservices.jwt.signature.signer.Signer; -import org.rootservices.jwt.signature.signer.factory.*; -import org.rootservices.jwt.signature.verifier.factory.VerifySignatureFactory; - - -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.Security; -import java.util.Base64; - -/** - * Created by tommackenzie on 8/13/15. - */ -public class AppFactory { - - public ObjectMapper objectMapper() { - return new ObjectMapper() - .setPropertyNamingStrategy( - PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES - ) - .configure(JsonParser.Feature.STRICT_DUPLICATE_DETECTION, true) - .registerModule(new Jdk8Module()) - .setSerializationInclusion(JsonInclude.Include.NON_NULL) - .setSerializationInclusion(JsonInclude.Include.NON_EMPTY); - } - - public Serializer serializer() { - return new Serializer(objectMapper()); - } - - public Base64.Decoder decoder() { - return Base64.getDecoder(); - } - - public Base64.Decoder urlDecoder() { - return Base64.getUrlDecoder(); - } - - public Base64.Encoder encoder() { - return Base64.getUrlEncoder().withoutPadding(); - } - - public JWTSerializer jwtSerializer() { - return new JWTSerializer( - serializer(), - encoder(), - decoder() - ); - } - - public PublicKeySignatureFactory publicKeySignatureFactory() { - return new PublicKeySignatureFactory(rsaKeyFactory()); - } - - public MacFactory macFactory() { - return new MacFactory(urlDecoder()); - } - - public PrivateKeySignatureFactory privateKeySignatureFactory() { - return new PrivateKeySignatureFactory(rsaKeyFactory()); - } - - public SignerFactory signerFactory() { - return new SignerFactory( - macFactory(), - privateKeySignatureFactory(), - jwtSerializer(), - encoder() - ); - } - - public VerifySignatureFactory verifySignatureFactory() { - return new VerifySignatureFactory(signerFactory(), publicKeySignatureFactory(), urlDecoder()); - } - - public VerifySignature verifySignature(Algorithm algorithm, Key key) throws InvalidAlgorithmException, InvalidJsonWebKeyException { - return verifySignatureFactory().makeVerifySignature(algorithm, key); - } - - public UnSecureJwtFactory unsecureJwtFactory(){ - return new UnSecureJwtFactory(); - } - - public SecureJwtFactory secureJwtFactory(Algorithm alg, Key jwk) throws InvalidAlgorithmException, InvalidJsonWebKeyException { - Signer signer = signerFactory().makeSigner(alg, jwk); - return new SecureJwtFactory(signer, alg, jwk.getKeyId()); - } - - public SecureJwtEncoder secureJwtEncoder(Algorithm alg, Key jwk) throws InvalidAlgorithmException, InvalidJsonWebKeyException { - SecureJwtFactory secureJwtFactory = null; - try { - secureJwtFactory = secureJwtFactory(alg, jwk); - } catch (InvalidAlgorithmException e) { - throw e; - } catch (InvalidJsonWebKeyException e) { - throw e; - } - - JWTSerializer jwtSerializer = jwtSerializer(); - - return new SecureJwtEncoder(secureJwtFactory, jwtSerializer); - } - - public UnSecureJwtEncoder unSecureJwtEncoder() { - return new UnSecureJwtEncoder(unsecureJwtFactory(), jwtSerializer()); - } - - public JcaPEMKeyConverter jcaPEMKeyConverter() { - Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); - return new JcaPEMKeyConverter().setProvider("BC"); - } - - protected KeyFactory rsaKeyFactory() { - KeyFactory RSAKeyFactory = null; - try { - RSAKeyFactory = KeyFactory.getInstance("RSA"); - } catch (NoSuchAlgorithmException e) { - // will never reach here. - e.printStackTrace(); - } - return RSAKeyFactory; - } - - public PemToRSAKeyPair pemToRSAKeyPair() { - return new PemToRSAKeyPair(jcaPEMKeyConverter(), rsaKeyFactory()); - } - - public CSRToRSAPublicKey csrToRSAPublicKey() { - return new CSRToRSAPublicKey(); - } -} diff --git a/src/main/java/org/rootservices/jwt/config/JwtAppFactory.java b/src/main/java/org/rootservices/jwt/config/JwtAppFactory.java new file mode 100644 index 0000000..dff2b18 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/config/JwtAppFactory.java @@ -0,0 +1,236 @@ +package org.rootservices.jwt.config; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.PropertyNamingStrategy; +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.rootservices.jwt.jwe.serialization.direct.JweDirectDesializer; +import org.rootservices.jwt.jwe.serialization.direct.JweDirectSerializer; +import org.rootservices.jwt.jwe.serialization.rsa.JweRsaSerializer; +import org.rootservices.jwt.jws.serialization.SecureJwtSerializer; +import org.rootservices.jwt.exception.SignatureException; +import org.rootservices.jwt.serialization.JwtSerde; +import org.rootservices.jwt.serialization.Serdes; +import org.rootservices.jwt.serialization.UnSecureJwtSerializer; +import org.rootservices.jwt.entity.jwk.RSAPublicKey; +import org.rootservices.jwt.jwe.Transformation; +import org.rootservices.jwt.jwe.factory.CipherRSAFactory; +import org.rootservices.jwt.jwe.factory.CipherSymmetricFactory; +import org.rootservices.jwt.jwe.factory.exception.CipherException; +import org.rootservices.jwt.jwk.PrivateKeyFactory; +import org.rootservices.jwt.jwk.PublicKeyFactory; +import org.rootservices.jwt.jwk.SecretKeyFactory; +import org.rootservices.jwt.jws.signer.factory.rsa.exception.PublicKeyException; +import org.rootservices.jwt.serialization.HeaderDeserializer; +import org.rootservices.jwt.jwe.serialization.rsa.JweRsaDeserializer; +import org.rootservices.jwt.jws.signer.factory.exception.InvalidAlgorithmException; +import org.rootservices.jwt.jws.signer.factory.exception.InvalidJsonWebKeyException; +import org.rootservices.jwt.factory.SecureJwtFactory; +import org.rootservices.jwt.factory.UnSecureJwtFactory; +import org.rootservices.jwt.entity.jwk.Key; +import org.rootservices.jwt.entity.jwt.header.Algorithm; +import org.rootservices.jwt.jws.signer.factory.hmac.MacFactory; +import org.rootservices.jwt.jws.signer.factory.rsa.PrivateKeySignatureFactory; +import org.rootservices.jwt.jws.signer.factory.rsa.PublicKeySignatureFactory; +import org.rootservices.jwt.jws.verifier.VerifySignature; +import org.rootservices.jwt.jws.signer.Signer; +import org.rootservices.jwt.jws.signer.factory.*; +import org.rootservices.jwt.jws.verifier.factory.VerifySignatureFactory; + + +import javax.crypto.Cipher; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; + + +public class JwtAppFactory { + private static final Logger LOGGER = LogManager.getLogger(JwtAppFactory.class); + public static final String KEY_WAS_INVALID = "Could not construct Signer. Key was invalid."; + public static final String ALG_WAS_INVALID = "Could not construct Signer. Algorithm was invalid."; + public static final String RSA = "RSA"; + private static ObjectMapper objectMapper; + private static KeyFactory RSAKeyFactory; + + public ObjectMapper objectMapper() { + if (objectMapper == null) { + this.objectMapper = new ObjectMapper() + .setPropertyNamingStrategy( + PropertyNamingStrategy.SNAKE_CASE + ) + .configure(JsonParser.Feature.STRICT_DUPLICATE_DETECTION, true) + .registerModule(new Jdk8Module()) + .setSerializationInclusion(JsonInclude.Include.NON_NULL) + .setSerializationInclusion(JsonInclude.Include.NON_EMPTY); + } + return objectMapper; + } + + public Serdes serdes() { + return new Serdes(objectMapper()); + } + + public Base64.Decoder decoder() { + return Base64.getDecoder(); + } + + public Base64.Decoder urlDecoder() { + return Base64.getUrlDecoder(); + } + + public Base64.Encoder encoder() { + return Base64.getUrlEncoder().withoutPadding(); + } + + public HeaderDeserializer headerDeserializer() { + return new HeaderDeserializer(decoder(), serdes()); + } + + public JwtSerde jwtSerde() { + return new JwtSerde( + serdes(), + encoder(), + decoder() + ); + } + + public CipherRSAFactory cipherRSAFactory() { + return new CipherRSAFactory(); + } + + public CipherSymmetricFactory cipherSymmetricFactory() { + return new CipherSymmetricFactory(); + } + + public JweRsaDeserializer jweRsaDeserializer() { + + return new JweRsaDeserializer( + serdes(), + urlDecoder(), + privateKeyFactory(), + cipherRSAFactory(), + cipherSymmetricFactory() + ); + } + + public JweDirectDesializer jweDirectDesializer() { + return new JweDirectDesializer( + serdes(), + urlDecoder(), + cipherSymmetricFactory() + ); + } + + public PublicKeyFactory publicKeyFactory() { + return new PublicKeyFactory(rsaKeyFactory()); + } + + public PublicKeySignatureFactory publicKeySignatureFactory() { + return new PublicKeySignatureFactory(rsaKeyFactory()); + } + + public MacFactory macFactory() { + return new MacFactory(urlDecoder()); + } + + public PrivateKeyFactory privateKeyFactory() { + return new PrivateKeyFactory(rsaKeyFactory()); + } + + public PrivateKeySignatureFactory privateKeySignatureFactory() { + return new PrivateKeySignatureFactory(rsaKeyFactory()); + } + + public SignerFactory signerFactory() { + return new SignerFactory( + macFactory(), + privateKeySignatureFactory(), + jwtSerde(), + encoder() + ); + } + + public VerifySignatureFactory verifySignatureFactory() { + return new VerifySignatureFactory(signerFactory(), publicKeySignatureFactory(), urlDecoder()); + } + + public VerifySignature verifySignature(Algorithm algorithm, Key key) throws SignatureException { + return verifySignatureFactory().makeVerifySignature(algorithm, key); + } + + public UnSecureJwtFactory unsecureJwtFactory(){ + return new UnSecureJwtFactory(); + } + + public SecureJwtFactory secureJwtFactory(Algorithm alg, Key jwk) throws InvalidAlgorithmException, InvalidJsonWebKeyException { + Signer signer = signerFactory().makeSigner(alg, jwk); + return new SecureJwtFactory(signer, alg, jwk.getKeyId()); + } + + public SecureJwtSerializer secureJwtSerializer(Algorithm alg, Key jwk) throws SignatureException { + SecureJwtFactory secureJwtFactory; + try { + secureJwtFactory = secureJwtFactory(alg, jwk); + } catch (InvalidAlgorithmException e) { + throw new SignatureException(ALG_WAS_INVALID, e); + } catch (InvalidJsonWebKeyException e) { + throw new SignatureException(KEY_WAS_INVALID, e); + } + + JwtSerde jwtSerde = jwtSerde(); + + return new SecureJwtSerializer(secureJwtFactory, jwtSerde); + } + + public JweRsaSerializer jweRsaSerializer(RSAPublicKey jwk) throws PublicKeyException, CipherException { + java.security.interfaces.RSAPublicKey jdkKey; + try { + jdkKey = publicKeyFactory().makePublicKey(jwk); + } catch (PublicKeyException e) { + throw e; + } + + Cipher rsaEncryptCipher; + try { + rsaEncryptCipher = cipherRSAFactory().forEncrypt(Transformation.RSA_OAEP, jdkKey); + } catch (CipherException e) { + throw e; + } + + return new JweRsaSerializer( + serdes(), + encoder(), + rsaEncryptCipher, + new SecretKeyFactory(), + cipherSymmetricFactory() + ); + } + + public JweDirectSerializer jweDirectSerializer() { + + return new JweDirectSerializer( + serdes(), + encoder(), + cipherSymmetricFactory() + ); + } + + public UnSecureJwtSerializer unSecureJwtSerializer() { + return new UnSecureJwtSerializer(unsecureJwtFactory(), jwtSerde()); + } + + protected KeyFactory rsaKeyFactory() { + if (this.RSAKeyFactory == null) { + try { + RSAKeyFactory = KeyFactory.getInstance(RSA); + } catch (NoSuchAlgorithmException e) { + // will never reach here. + LOGGER.error(e.getMessage(), e); + } + } + return RSAKeyFactory; + } +} diff --git a/src/main/java/org/rootservices/jwt/entity/jwe/EncryptionAlgorithm.java b/src/main/java/org/rootservices/jwt/entity/jwe/EncryptionAlgorithm.java new file mode 100644 index 0000000..45fadc2 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/entity/jwe/EncryptionAlgorithm.java @@ -0,0 +1,18 @@ +package org.rootservices.jwt.entity.jwe; + +import com.fasterxml.jackson.annotation.JsonValue; + +public enum EncryptionAlgorithm { + AES_GCM_256 ("A256GCM"); + + private String value; + + EncryptionAlgorithm(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } +} diff --git a/src/main/java/org/rootservices/jwt/entity/jwk/KeyType.java b/src/main/java/org/rootservices/jwt/entity/jwk/KeyType.java index 974138e..3d77881 100644 --- a/src/main/java/org/rootservices/jwt/entity/jwk/KeyType.java +++ b/src/main/java/org/rootservices/jwt/entity/jwk/KeyType.java @@ -9,11 +9,10 @@ public enum KeyType { private String value; - private KeyType(String value) { + KeyType(String value) { this.value = value; } - public String getValue() { return value; } diff --git a/src/main/java/org/rootservices/jwt/entity/jwt/JsonWebToken.java b/src/main/java/org/rootservices/jwt/entity/jwt/JsonWebToken.java index 625b670..89d6581 100644 --- a/src/main/java/org/rootservices/jwt/entity/jwt/JsonWebToken.java +++ b/src/main/java/org/rootservices/jwt/entity/jwt/JsonWebToken.java @@ -11,7 +11,7 @@ public class JsonWebToken { private Header header; private Claims claims; - private Optional signature = Optional.empty(); + private Optional signature = Optional.empty(); private Optional jwt = Optional.empty(); public JsonWebToken() {} @@ -43,11 +43,11 @@ public void setClaims(Claims claims) { this.claims = claims; } - public Optional getSignature() { + public Optional getSignature() { return signature; } - public void setSignature(Optional signature) { + public void setSignature(Optional signature) { this.signature = signature; } diff --git a/src/main/java/org/rootservices/jwt/entity/jwt/header/Algorithm.java b/src/main/java/org/rootservices/jwt/entity/jwt/header/Algorithm.java index 3006442..136ae04 100644 --- a/src/main/java/org/rootservices/jwt/entity/jwt/header/Algorithm.java +++ b/src/main/java/org/rootservices/jwt/entity/jwt/header/Algorithm.java @@ -8,14 +8,18 @@ */ @JsonFormat(shape = JsonFormat.Shape.OBJECT) public enum Algorithm { - NONE ("none"), - HS256 ("HS256"), - RS256 ("RS256"); + NONE ("none", AlgorithmFor.JWS), + HS256 ("HS256", AlgorithmFor.JWS), + RS256 ("RS256", AlgorithmFor.JWS), + DIRECT ("dir", AlgorithmFor.JWE), + RSAES_OAEP ("RSA-OAEP", AlgorithmFor.JWE); private String value; + private AlgorithmFor algorithmFor; - Algorithm(String value) { + Algorithm(String value, AlgorithmFor algorithmFor) { this.value = value; + this.algorithmFor = algorithmFor; } @JsonValue @@ -26,4 +30,8 @@ public String getValue() { public void setValue(String value) { this.value = value; } + + public AlgorithmFor getAlgorithmFor() { + return algorithmFor; + } } diff --git a/src/main/java/org/rootservices/jwt/entity/jwt/header/AlgorithmFor.java b/src/main/java/org/rootservices/jwt/entity/jwt/header/AlgorithmFor.java new file mode 100644 index 0000000..a0d1a8a --- /dev/null +++ b/src/main/java/org/rootservices/jwt/entity/jwt/header/AlgorithmFor.java @@ -0,0 +1,5 @@ +package org.rootservices.jwt.entity.jwt.header; + +public enum AlgorithmFor { + JWS, JWE +} diff --git a/src/main/java/org/rootservices/jwt/entity/jwt/header/Header.java b/src/main/java/org/rootservices/jwt/entity/jwt/header/Header.java index c69c9c7..a56f9eb 100644 --- a/src/main/java/org/rootservices/jwt/entity/jwt/header/Header.java +++ b/src/main/java/org/rootservices/jwt/entity/jwt/header/Header.java @@ -1,6 +1,8 @@ package org.rootservices.jwt.entity.jwt.header; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import org.rootservices.jwt.entity.jwe.EncryptionAlgorithm; import java.util.Optional; @@ -11,11 +13,13 @@ */ public class Header { @JsonProperty(value="typ") - Optional type; + private Optional type = Optional.empty();; @JsonProperty(value="alg") - Algorithm algorithm; + private Algorithm algorithm; @JsonProperty(value="kid") private Optional keyId = Optional.empty(); + @JsonProperty(value="enc") + private Optional encryptionAlgorithm = Optional.empty(); public Optional getType() { return type; @@ -40,4 +44,12 @@ public Optional getKeyId() { public void setKeyId(Optional keyId) { this.keyId = keyId; } + + public Optional getEncryptionAlgorithm() { + return encryptionAlgorithm; + } + + public void setEncryptionAlgorithm(Optional encryptionAlgorithm) { + this.encryptionAlgorithm = encryptionAlgorithm; + } } diff --git a/src/main/java/org/rootservices/jwt/exception/InvalidJWT.java b/src/main/java/org/rootservices/jwt/exception/InvalidJWT.java new file mode 100644 index 0000000..f2266d3 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/exception/InvalidJWT.java @@ -0,0 +1,7 @@ +package org.rootservices.jwt.exception; + +public class InvalidJWT extends Exception { + public InvalidJWT(String message) { + super(message); + } +} diff --git a/src/main/java/org/rootservices/jwt/exception/SignatureException.java b/src/main/java/org/rootservices/jwt/exception/SignatureException.java new file mode 100644 index 0000000..a9e54d8 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/exception/SignatureException.java @@ -0,0 +1,10 @@ +package org.rootservices.jwt.exception; + +/** + * Represents when a Signer could not be constructed due to a invalid key or algorithm. + */ +public class SignatureException extends Exception { + public SignatureException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/rootservices/jwt/factory/SecureJwtFactory.java b/src/main/java/org/rootservices/jwt/factory/SecureJwtFactory.java index eb03e3e..53343eb 100644 --- a/src/main/java/org/rootservices/jwt/factory/SecureJwtFactory.java +++ b/src/main/java/org/rootservices/jwt/factory/SecureJwtFactory.java @@ -5,14 +5,12 @@ import org.rootservices.jwt.entity.jwt.header.Algorithm; import org.rootservices.jwt.entity.jwt.header.Header; import org.rootservices.jwt.entity.jwt.header.TokenType; -import org.rootservices.jwt.serializer.exception.JwtToJsonException; -import org.rootservices.jwt.signature.signer.Signer; +import org.rootservices.jwt.serialization.exception.JwtToJsonException; +import org.rootservices.jwt.jws.signer.Signer; import java.util.Optional; -/** - * Created by tommackenzie on 9/15/15. - */ + public class SecureJwtFactory { private Signer signer; private Algorithm algorithm; @@ -34,7 +32,7 @@ public JsonWebToken makeJwt(Claims claimNames) throws JwtToJsonException { jwt.setHeader(header); jwt.setClaims(claimNames); - String signature = signer.run(jwt); + byte[] signature = signer.run(jwt); jwt.setSignature(Optional.of(signature)); return jwt; diff --git a/src/main/java/org/rootservices/jwt/factory/UnSecureJwtFactory.java b/src/main/java/org/rootservices/jwt/factory/UnSecureJwtFactory.java index 35a00c4..d54699f 100644 --- a/src/main/java/org/rootservices/jwt/factory/UnSecureJwtFactory.java +++ b/src/main/java/org/rootservices/jwt/factory/UnSecureJwtFactory.java @@ -20,7 +20,7 @@ public JsonWebToken makeJwt(Claims claimNames) { JsonWebToken jwt = new JsonWebToken(); jwt.setHeader(header); jwt.setClaims(claimNames); - jwt.setSignature(Optional.empty()); + jwt.setSignature(Optional.empty()); return jwt; } diff --git a/src/main/java/org/rootservices/jwt/jwe/Transformation.java b/src/main/java/org/rootservices/jwt/jwe/Transformation.java new file mode 100644 index 0000000..05c72c7 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/jwe/Transformation.java @@ -0,0 +1,17 @@ +package org.rootservices.jwt.jwe; + +public enum Transformation { + // RSA_OAEP ("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"), + RSA_OAEP ("RSA/ECB/OAEPPadding"), + AES_GCM_NO_PADDING ("AES/GCM/NoPadding"); + + private String value; + + Transformation(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/src/main/java/org/rootservices/jwt/jwe/entity/JWE.java b/src/main/java/org/rootservices/jwt/jwe/entity/JWE.java new file mode 100644 index 0000000..d771892 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/jwe/entity/JWE.java @@ -0,0 +1,61 @@ +package org.rootservices.jwt.jwe.entity; + +import org.rootservices.jwt.entity.jwt.header.Header; + +public class JWE { + private Header header; + private byte[] payload; + private byte[] cek; + private byte[] iv; + private byte[] authTag; + + public JWE() {} + + public JWE(Header header, byte[] payload, byte[] cek, byte[] iv, byte[] authTag) { + this.header = header; + this.payload = payload; + this.cek = cek; + this.iv = iv; + this.authTag = authTag; + } + + public Header getHeader() { + return header; + } + + public void setHeader(Header header) { + this.header = header; + } + + public byte[] getPayload() { + return payload; + } + + public void setPayload(byte[] payload) { + this.payload = payload; + } + + public byte[] getCek() { + return cek; + } + + public void setCek(byte[] cek) { + this.cek = cek; + } + + public byte[] getIv() { + return iv; + } + + public void setIv(byte[] iv) { + this.iv = iv; + } + + public byte[] getAuthTag() { + return authTag; + } + + public void setAuthTag(byte[] authTag) { + this.authTag = authTag; + } +} diff --git a/src/main/java/org/rootservices/jwt/jwe/exception/EncryptException.java b/src/main/java/org/rootservices/jwt/jwe/exception/EncryptException.java new file mode 100644 index 0000000..a505ee6 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/jwe/exception/EncryptException.java @@ -0,0 +1,7 @@ +package org.rootservices.jwt.jwe.exception; + +public class EncryptException extends Exception { + public EncryptException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/rootservices/jwt/jwe/factory/CipherRSAFactory.java b/src/main/java/org/rootservices/jwt/jwe/factory/CipherRSAFactory.java new file mode 100644 index 0000000..ab58ff8 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/jwe/factory/CipherRSAFactory.java @@ -0,0 +1,65 @@ +package org.rootservices.jwt.jwe.factory; + +import org.rootservices.jwt.jwe.Transformation; +import org.rootservices.jwt.jwe.factory.exception.CipherException; + +import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.OAEPParameterSpec; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.spec.AlgorithmParameterSpec; + +/** + * https://docs.oracle.com/javase/9/docs/api/javax/crypto/spec/OAEPParameterSpec.html + * https://security.stackexchange.com/questions/97548/breaking-down-rsa-ecb-oaepwithsha-256andmgf1padding + */ +public class CipherRSAFactory { + public static final String ALGORITHM_WAS_INVALID = "Algorithm, %s, was invalid"; + public static final String PADDING_WAS_INVALID = "Padding for algorithm, %s, was invalid"; + public static final String KEY_WAS_INVALID_INIT_CIPHER = "Key was invalid when initializing cipher"; + public static final String ALGORITHM_WAS_INVALID_INIT_CIPHER = "Algorithm, %s, was invalid when initializing cipher"; + + public Cipher forEncrypt(Transformation transformation, Key key) throws CipherException { + AlgorithmParameterSpec spec = makeSpec(transformation); + Cipher cipher = makeCipher(transformation, key, Cipher.ENCRYPT_MODE, spec); + return cipher; + } + + public Cipher forDecrypt(Transformation transformation, Key key) throws CipherException { + AlgorithmParameterSpec spec = makeSpec(transformation); + Cipher cipher = makeCipher(transformation, key, Cipher.DECRYPT_MODE, spec); + return cipher; + } + + protected AlgorithmParameterSpec makeSpec(Transformation transformation) { + AlgorithmParameterSpec spec = null; + if (transformation == Transformation.RSA_OAEP) { + spec = OAEPParameterSpec.DEFAULT; + } + return spec; + } + + protected Cipher makeCipher(Transformation transformation, Key key, int mode, AlgorithmParameterSpec spec) throws CipherException { + Cipher cipher; + try { + cipher = Cipher.getInstance(transformation.getValue()); + } catch (NoSuchAlgorithmException e) { + throw new CipherException(String.format(ALGORITHM_WAS_INVALID, transformation.getValue()), e); + } catch (NoSuchPaddingException e) { + throw new CipherException(String.format(PADDING_WAS_INVALID, transformation.getValue()), e); + } + + try { + cipher.init(mode, key, spec); + } catch (InvalidKeyException e) { + throw new CipherException(KEY_WAS_INVALID_INIT_CIPHER, e); + } catch (InvalidAlgorithmParameterException e) { + throw new CipherException(String.format(ALGORITHM_WAS_INVALID_INIT_CIPHER, transformation.getValue()), e); + } + + return cipher; + } +} diff --git a/src/main/java/org/rootservices/jwt/jwe/factory/CipherSymmetricFactory.java b/src/main/java/org/rootservices/jwt/jwe/factory/CipherSymmetricFactory.java new file mode 100644 index 0000000..ee52487 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/jwe/factory/CipherSymmetricFactory.java @@ -0,0 +1,101 @@ +package org.rootservices.jwt.jwe.factory; + +import org.rootservices.jwt.jwe.Transformation; +import org.rootservices.jwt.jwe.factory.exception.CipherException; +import org.rootservices.jwt.jwk.KeyAlgorithm; + +import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.OAEPParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.security.*; +import java.security.spec.AlgorithmParameterSpec; + +/** + * AES-GCM + * https://wiki.sei.cmu.edu/confluence/display/java/MSC61-J.+Do+not+use+insecure+or+weak+cryptographic+algorithms + * https://gist.github.com/praseodym/f2499b3e14d872fe5b4a + * + * OAEP + * https://stackoverflow.com/questions/32161720/breaking-down-rsa-ecb-oaepwithsha-256andmgf1padding + * https://docs.oracle.com/javase/9/docs/api/javax/crypto/spec/OAEPParameterSpec.html + * https://docs.oracle.com/cd/E23943_01/security.1111/e10037/crypto.htm#BJFCICAE + * + * https://docs.oracle.com/javase/9/docs/api/javax/crypto/spec/OAEPParameterSpec.html + * https://security.stackexchange.com/questions/97548/breaking-down-rsa-ecb-oaepwithsha-256andmgf1padding + */ +public class CipherSymmetricFactory { + public static final int GCM_TAG_LENGTH = 128; + public static final int GCM_IV_LENGTH = 96; + public static final String ALGORITHM_WAS_INVALID = "Algorithm, %s, was invalid"; + public static final String PADDING_WAS_INVALID = "Padding for algorithm, %s, was invalid"; + public static final String KEY_WAS_INVALID_INIT_CIPHER = "Key was invalid when initializing cipher"; + public static final String ALGORITHM_WAS_INVALID_INIT_CIPHER = "Algorithm, %s, was invalid when initializing cipher"; + + private static SecureRandom secureRandom = new SecureRandom(); + + public Cipher forEncrypt(Transformation transformation, Key key, byte[] aad) throws CipherException { + + byte[] initVector = makeInitVector(); + AlgorithmParameterSpec spec = makeSpec(transformation, initVector); + Cipher cipher = makeCipher(transformation, key, Cipher.ENCRYPT_MODE, spec, aad); + return cipher; + } + + public Cipher forDecrypt(Transformation transformation, Key key, byte[] initVector, byte[] aad) throws CipherException { + AlgorithmParameterSpec spec = makeSpec(transformation, initVector); + Cipher cipher = makeCipher(transformation, key, Cipher.DECRYPT_MODE, spec, aad); + return cipher; + } + + public Cipher forDecrypt(Transformation transformation, byte[] cek, byte[] initVector, byte[] aad) throws CipherException { + SecretKey key = new SecretKeySpec(cek, KeyAlgorithm.AES.getValue()); + Cipher cipher; + try { + cipher = forDecrypt(transformation, key, initVector, aad); + } catch (CipherException e) { + throw e; + } + + return cipher; + } + + public byte[] makeInitVector() { + byte[] initVector = new byte[GCM_IV_LENGTH]; + secureRandom.nextBytes(initVector); + return initVector; + } + + protected AlgorithmParameterSpec makeSpec(Transformation transformation, byte[] initVector) { + AlgorithmParameterSpec spec = null; + if (transformation == Transformation.AES_GCM_NO_PADDING) { + spec = new GCMParameterSpec(GCM_TAG_LENGTH, initVector); + } + return spec; + } + + protected Cipher makeCipher(Transformation transformation, Key key, int mode, AlgorithmParameterSpec spec, byte[] aad) throws CipherException { + Cipher cipher; + try { + cipher = Cipher.getInstance(transformation.getValue()); + } catch (NoSuchAlgorithmException e) { + throw new CipherException(String.format(ALGORITHM_WAS_INVALID, transformation.getValue()), e); + } catch (NoSuchPaddingException e) { + throw new CipherException(String.format(PADDING_WAS_INVALID, transformation.getValue()), e); + } + + try { + cipher.init(mode, key, spec); + } catch (InvalidKeyException e) { + throw new CipherException(KEY_WAS_INVALID_INIT_CIPHER, e); + } catch (InvalidAlgorithmParameterException e) { + throw new CipherException(String.format(ALGORITHM_WAS_INVALID_INIT_CIPHER, transformation.getValue()), e); + } + + cipher.updateAAD(aad); + return cipher; + } + +} diff --git a/src/main/java/org/rootservices/jwt/jwe/factory/exception/CipherException.java b/src/main/java/org/rootservices/jwt/jwe/factory/exception/CipherException.java new file mode 100644 index 0000000..b7c21e8 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/jwe/factory/exception/CipherException.java @@ -0,0 +1,7 @@ +package org.rootservices.jwt.jwe.factory.exception; + +public class CipherException extends Exception { + public CipherException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/rootservices/jwt/jwe/serialization/JweDeserializer.java b/src/main/java/org/rootservices/jwt/jwe/serialization/JweDeserializer.java new file mode 100644 index 0000000..284c36f --- /dev/null +++ b/src/main/java/org/rootservices/jwt/jwe/serialization/JweDeserializer.java @@ -0,0 +1,33 @@ +package org.rootservices.jwt.jwe.serialization; + +import org.rootservices.jwt.entity.jwk.Key; +import org.rootservices.jwt.jwe.entity.JWE; +import org.rootservices.jwt.jwe.factory.exception.CipherException; +import org.rootservices.jwt.jwe.serialization.exception.KeyException; +import org.rootservices.jwt.serialization.exception.DecryptException; +import org.rootservices.jwt.serialization.exception.JsonToJwtException; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public interface JweDeserializer { + String JWT_SPLITTER = "\\."; + String COMPACT_JWE_INVALID = "Compact JWE is invalid"; + String COULD_NOT_DECRYPT_ENCRYPTED_KEY = "Could not Decrypt encrypted key"; + String COULD_NOT_DECRYPT_CIPHER_TEXT = "Could not decrypt cipher text"; + String COULD_NOT_COMBINE_CIPHER_TEXT_AND_AT = "Could not combine cipher text with authentication tag"; + + JWE stringToJWE(String compactJWE, Key cek) throws JsonToJwtException, DecryptException, CipherException, KeyException; + + default byte[] cipherTextWithAuthTag(byte[] cipherText, byte[] authTag) throws DecryptException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream( ); + try { + outputStream.write(cipherText); + outputStream.write(authTag); + } catch (IOException e) { + throw new DecryptException(COULD_NOT_COMBINE_CIPHER_TEXT_AND_AT, e); + } + + return outputStream.toByteArray(); + } +} diff --git a/src/main/java/org/rootservices/jwt/jwe/serialization/JweSerializer.java b/src/main/java/org/rootservices/jwt/jwe/serialization/JweSerializer.java new file mode 100644 index 0000000..5929d2a --- /dev/null +++ b/src/main/java/org/rootservices/jwt/jwe/serialization/JweSerializer.java @@ -0,0 +1,59 @@ +package org.rootservices.jwt.jwe.serialization; + +import org.rootservices.jwt.jwe.entity.JWE; +import org.rootservices.jwt.jwe.factory.CipherSymmetricFactory; +import org.rootservices.jwt.jwe.factory.exception.CipherException; +import org.rootservices.jwt.serialization.exception.EncryptException; +import org.rootservices.jwt.serialization.exception.JsonToJwtException; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.List; + +public interface JweSerializer { + byte[] DELIMITER = ".".getBytes(); + String COULD_NOT_COMPACT = "Could not compact"; + ByteArrayOutputStream JWEToCompact(JWE jwe) throws JsonToJwtException, CipherException, EncryptException; + + default byte[] extractCipherText(byte[] cipherTextWithAuthTag) { + int tagLength = CipherSymmetricFactory.GCM_TAG_LENGTH / Byte.SIZE; + int cipherTextEnd = cipherTextWithAuthTag.length - tagLength; + + byte[] cipherText = new byte[cipherTextEnd]; + System.arraycopy(cipherTextWithAuthTag, 0, cipherText, 0, cipherTextEnd); + return cipherText; + } + + default byte[] extractAuthTag(byte[] cipherTextWithAuthTag) { + int tagLength = CipherSymmetricFactory.GCM_TAG_LENGTH / Byte.SIZE; + int cipherTextEnd = cipherTextWithAuthTag.length - tagLength; + + byte[] authTag = new byte[tagLength]; + System.arraycopy(cipherTextWithAuthTag, cipherTextEnd, authTag, 0, tagLength); + return authTag; + } + + default ByteArrayOutputStream toCompact(List jweParts) throws EncryptException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream( ); + + for(int i=0; i < jweParts.size(); i++) { + if (jweParts.get(i) != null) { + try { + outputStream.write(jweParts.get(i)); + } catch (IOException e) { + throw new EncryptException(COULD_NOT_COMPACT, e); + } + } + + if (i < jweParts.size() - 1) { + try { + outputStream.write(DELIMITER); + } catch (IOException e) { + throw new EncryptException(COULD_NOT_COMPACT, e); + } + } + } + + return outputStream; + } +} diff --git a/src/main/java/org/rootservices/jwt/jwe/serialization/direct/JweDirectDesializer.java b/src/main/java/org/rootservices/jwt/jwe/serialization/direct/JweDirectDesializer.java new file mode 100644 index 0000000..e8c96b9 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/jwe/serialization/direct/JweDirectDesializer.java @@ -0,0 +1,72 @@ +package org.rootservices.jwt.jwe.serialization.direct; + +import org.rootservices.jwt.entity.jwk.Key; +import org.rootservices.jwt.entity.jwk.SymmetricKey; +import org.rootservices.jwt.entity.jwt.header.Header; +import org.rootservices.jwt.jwe.Transformation; +import org.rootservices.jwt.jwe.entity.JWE; +import org.rootservices.jwt.jwe.factory.CipherSymmetricFactory; +import org.rootservices.jwt.jwe.factory.exception.CipherException; +import org.rootservices.jwt.jwe.serialization.JweDeserializer; +import org.rootservices.jwt.serialization.Serdes; +import org.rootservices.jwt.serialization.exception.DecryptException; +import org.rootservices.jwt.serialization.exception.JsonException; +import org.rootservices.jwt.serialization.exception.JsonToJwtException; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + + +public class JweDirectDesializer implements JweDeserializer { + private Serdes serdes; + private Base64.Decoder decoder; + private CipherSymmetricFactory cipherSymmetricFactory; + + public JweDirectDesializer(Serdes serdes, Base64.Decoder decoder, CipherSymmetricFactory cipherSymmetricFactory) { + this.serdes = serdes; + this.decoder = decoder; + this.cipherSymmetricFactory = cipherSymmetricFactory; + } + + @Override + public JWE stringToJWE(String compactJWE, Key key) throws JsonToJwtException, DecryptException, CipherException { + String[] jweParts = compactJWE.split(JWT_SPLITTER); + byte[] protectedHeader = decoder.decode(jweParts[0]); + byte[] initVector = decoder.decode(jweParts[2]); + byte[] cipherText = decoder.decode(jweParts[3]); + byte[] authenticationTag = decoder.decode(jweParts[4]); + + Header header; + try { + header = (Header) serdes.jsonBytesToObject(protectedHeader, Header.class); + } catch (JsonException e) { + throw new JsonToJwtException(COMPACT_JWE_INVALID, e); + } + + byte[] aad = jweParts[0].getBytes(StandardCharsets.US_ASCII); + + byte[] cek = decoder.decode(((SymmetricKey) key).getKey().getBytes()); + Cipher symmetricCipher; + try { + symmetricCipher = cipherSymmetricFactory.forDecrypt(Transformation.AES_GCM_NO_PADDING, cek, initVector, aad); + } catch (CipherException e) { + throw e; + } + + byte[] cipherTextWithAuthTag = cipherTextWithAuthTag(cipherText, authenticationTag); + + byte[] payload; + try { + payload = symmetricCipher.doFinal(cipherTextWithAuthTag); + } catch (IllegalBlockSizeException e) { + throw new DecryptException(COULD_NOT_DECRYPT_CIPHER_TEXT, e); + } catch (BadPaddingException e) { + throw new DecryptException(COULD_NOT_DECRYPT_CIPHER_TEXT, e); + } + + return new JWE(header, payload, cek, initVector, authenticationTag); + } +} diff --git a/src/main/java/org/rootservices/jwt/jwe/serialization/direct/JweDirectSerializer.java b/src/main/java/org/rootservices/jwt/jwe/serialization/direct/JweDirectSerializer.java new file mode 100644 index 0000000..76a9379 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/jwe/serialization/direct/JweDirectSerializer.java @@ -0,0 +1,95 @@ +package org.rootservices.jwt.jwe.serialization.direct; + +import org.rootservices.jwt.jwe.Transformation; +import org.rootservices.jwt.jwe.entity.JWE; +import org.rootservices.jwt.jwe.factory.CipherSymmetricFactory; +import org.rootservices.jwt.jwe.factory.exception.CipherException; +import org.rootservices.jwt.jwe.serialization.JweSerializer; +import org.rootservices.jwt.jwk.KeyAlgorithm; +import org.rootservices.jwt.serialization.Serdes; +import org.rootservices.jwt.serialization.exception.EncryptException; +import org.rootservices.jwt.serialization.exception.JsonException; +import org.rootservices.jwt.serialization.exception.JsonToJwtException; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; + +public class JweDirectSerializer implements JweSerializer { + public static final String COULD_NOT_ENCRYPT = "Could not encrypt content"; + public static final String HEADER_IS_INVALID = "Header is invalid. Could not serialize to it to JSON"; + + private Serdes serdes; + private Base64.Encoder encoder; + private CipherSymmetricFactory cipherSymmetricFactory; + + public JweDirectSerializer(Serdes serdes, Base64.Encoder encoder, CipherSymmetricFactory cipherSymmetricFactory) { + this.serdes = serdes; + this.encoder = encoder; + this.cipherSymmetricFactory = cipherSymmetricFactory; + } + + /** + * Generates a compact JWE. + * + * Ignores the value for the jwe iv and generates a new one. + * + * The variable symmetricCipher is a propagating dependency. It cannot be reused per + * encryption attempt because it requires a new iv and aad per attempt. + * + * @param jwe must have values for header, cek, payload. Ignores the value for iv and generates a new one. + * @return a ByteArrayOutputStream that is a compact JWE + * @throws JsonToJwtException if the header cannot be serialized. + * @throws CipherException if the cipher for encryption could not be instantiated + * @throws EncryptException if the payload could not be encrypted + */ + @Override + public ByteArrayOutputStream JWEToCompact(JWE jwe) throws JsonToJwtException, CipherException, EncryptException { + byte[] protectedHeader; + try { + protectedHeader = serdes.objectToByte(jwe.getHeader()); + } catch (JsonException e) { + throw new JsonToJwtException(HEADER_IS_INVALID, e); + } + + byte[] aad = encoder.encode(protectedHeader); + + SecretKey key = new SecretKeySpec(jwe.getCek(), KeyAlgorithm.AES.getValue()); + + Cipher symmetricCipher; + try { + symmetricCipher = cipherSymmetricFactory.forEncrypt(Transformation.AES_GCM_NO_PADDING, key, aad); + } catch (CipherException e) { + throw e; + } + + byte[] cipherTextWithAuthTag; + try { + cipherTextWithAuthTag = symmetricCipher.doFinal(jwe.getPayload()); + } catch (IllegalBlockSizeException e) { + throw new EncryptException(COULD_NOT_ENCRYPT, e); + } catch (BadPaddingException e) { + throw new EncryptException(COULD_NOT_ENCRYPT, e); + } + + + byte[] initVector = symmetricCipher.getIV(); + byte[] cipherText = extractCipherText(cipherTextWithAuthTag); + byte[] authTag = extractAuthTag(cipherTextWithAuthTag); + + List jweParts = new ArrayList<>(); + jweParts.add(encoder.encode(protectedHeader)); + jweParts.add(null); + jweParts.add(encoder.encode(initVector)); + jweParts.add(encoder.encode(cipherText)); + jweParts.add(encoder.encode(authTag)); + + return toCompact(jweParts); + } +} diff --git a/src/main/java/org/rootservices/jwt/jwe/serialization/exception/KeyException.java b/src/main/java/org/rootservices/jwt/jwe/serialization/exception/KeyException.java new file mode 100644 index 0000000..5d3dae6 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/jwe/serialization/exception/KeyException.java @@ -0,0 +1,7 @@ +package org.rootservices.jwt.jwe.serialization.exception; + +public class KeyException extends Exception { + public KeyException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/rootservices/jwt/jwe/serialization/rsa/JweRsaDeserializer.java b/src/main/java/org/rootservices/jwt/jwe/serialization/rsa/JweRsaDeserializer.java new file mode 100644 index 0000000..4c874a0 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/jwe/serialization/rsa/JweRsaDeserializer.java @@ -0,0 +1,104 @@ +package org.rootservices.jwt.jwe.serialization.rsa; + +import org.rootservices.jwt.entity.jwk.Key; +import org.rootservices.jwt.entity.jwk.RSAKeyPair; +import org.rootservices.jwt.jwe.Transformation; +import org.rootservices.jwt.jwe.entity.JWE; +import org.rootservices.jwt.jwe.factory.CipherRSAFactory; +import org.rootservices.jwt.jwe.factory.CipherSymmetricFactory; +import org.rootservices.jwt.jwe.factory.exception.CipherException; +import org.rootservices.jwt.entity.jwt.header.Header; +import org.rootservices.jwt.jwe.serialization.JweDeserializer; +import org.rootservices.jwt.jwe.serialization.exception.KeyException; +import org.rootservices.jwt.jwk.PrivateKeyFactory; +import org.rootservices.jwt.jws.signer.factory.rsa.exception.PrivateKeyException; +import org.rootservices.jwt.serialization.Serdes; +import org.rootservices.jwt.serialization.exception.DecryptException; +import org.rootservices.jwt.serialization.exception.JsonException; +import org.rootservices.jwt.serialization.exception.JsonToJwtException; + + +import javax.crypto.*; + +import java.nio.charset.StandardCharsets; +import java.security.interfaces.RSAPrivateCrtKey; +import java.util.Base64; + +public class JweRsaDeserializer implements JweDeserializer { + + private Serdes serdes; + private Base64.Decoder decoder; + private PrivateKeyFactory privateKeyFactory; + private CipherRSAFactory cipherRSAFactory; + private CipherSymmetricFactory cipherSymmetricFactory; + + public JweRsaDeserializer(Serdes serdes, Base64.Decoder decoder, PrivateKeyFactory privateKeyFactory, CipherRSAFactory cipherRSAFactory, CipherSymmetricFactory cipherSymmetricFactory) { + this.serdes = serdes; + this.decoder = decoder; + this.privateKeyFactory = privateKeyFactory; + this.cipherRSAFactory = cipherRSAFactory; + this.cipherSymmetricFactory = cipherSymmetricFactory; + } + + public JWE stringToJWE(String compactJWE, Key key) throws JsonToJwtException, DecryptException, CipherException, KeyException { + String[] jweParts = compactJWE.split(JWT_SPLITTER); + byte[] protectedHeader = decoder.decode(jweParts[0]); + byte[] encryptedKey = decoder.decode(jweParts[1]); + byte[] initVector = decoder.decode(jweParts[2]); + byte[] cipherText = decoder.decode(jweParts[3]); + byte[] authenticationTag = decoder.decode(jweParts[4]); + + Header header; + try { + header = (Header) serdes.jsonBytesToObject(protectedHeader, Header.class); + } catch (JsonException e) { + throw new JsonToJwtException(COMPACT_JWE_INVALID, e); + } + + RSAKeyPair keyPair = (RSAKeyPair) key; + RSAPrivateCrtKey jdkKey; + try { + jdkKey = privateKeyFactory.makePrivateKey(keyPair); + } catch (PrivateKeyException e) { + throw new KeyException("", e); + } + + Cipher rsaDecryptCipher; + try { + rsaDecryptCipher = cipherRSAFactory.forDecrypt(Transformation.RSA_OAEP, jdkKey); + } catch (CipherException e) { + throw e; + } + + byte[] cek; + try { + cek = rsaDecryptCipher.doFinal(encryptedKey); + } catch (IllegalBlockSizeException e) { + throw new DecryptException(COULD_NOT_DECRYPT_ENCRYPTED_KEY, e); + } catch (BadPaddingException e) { + throw new DecryptException(COULD_NOT_DECRYPT_ENCRYPTED_KEY, e); + } + + byte[] aad = jweParts[0].getBytes(StandardCharsets.US_ASCII); + + Cipher symmetricCipher; + try { + symmetricCipher = cipherSymmetricFactory.forDecrypt(Transformation.AES_GCM_NO_PADDING, cek, initVector, aad); + } catch (CipherException e) { + throw e; + } + + byte[] cipherTextWithAuthTag = cipherTextWithAuthTag(cipherText, authenticationTag); + + byte[] payload; + try { + payload = symmetricCipher.doFinal(cipherTextWithAuthTag); + } catch (IllegalBlockSizeException e) { + throw new DecryptException(COULD_NOT_DECRYPT_CIPHER_TEXT, e); + } catch (BadPaddingException e) { + throw new DecryptException(COULD_NOT_DECRYPT_CIPHER_TEXT, e); + } + + return new JWE(header, payload, cek, initVector, authenticationTag); + } +} diff --git a/src/main/java/org/rootservices/jwt/jwe/serialization/rsa/JweRsaSerializer.java b/src/main/java/org/rootservices/jwt/jwe/serialization/rsa/JweRsaSerializer.java new file mode 100644 index 0000000..3b59e41 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/jwe/serialization/rsa/JweRsaSerializer.java @@ -0,0 +1,112 @@ +package org.rootservices.jwt.jwe.serialization.rsa; + +import org.rootservices.jwt.jwe.Transformation; +import org.rootservices.jwt.jwe.entity.JWE; +import org.rootservices.jwt.jwe.factory.CipherSymmetricFactory; +import org.rootservices.jwt.jwe.factory.exception.CipherException; +import org.rootservices.jwt.jwe.serialization.JweSerializer; +import org.rootservices.jwt.jwk.KeyAlgorithm; +import org.rootservices.jwt.jwk.SecretKeyFactory; +import org.rootservices.jwt.jwk.exception.SecretKeyException; +import org.rootservices.jwt.serialization.Serdes; +import org.rootservices.jwt.serialization.exception.EncryptException; +import org.rootservices.jwt.serialization.exception.JsonException; +import org.rootservices.jwt.serialization.exception.JsonToJwtException; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.SecretKey; +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; + +public class JweRsaSerializer implements JweSerializer { + public static final String COULD_NOT_ENCRYPT_CEK = "Could not encrypt Content Encryption Key"; + public static final String COULD_NOT_ENCRYPT = "Could not encrypt content"; + public static final String HEADER_IS_INVALID = "Header is invalid. Could not serialize to it to JSON"; + public static final String FAILED_TO_CREATE_CONTENT_ENCRYPTION_KEY = "Failed to create Content Encryption Key"; + private Serdes serdes; + private Base64.Encoder encoder; + private Cipher RSAEncryptCipher; + private SecretKeyFactory secretKeyFactory; + private CipherSymmetricFactory cipherSymmetricFactory; + + public JweRsaSerializer(Serdes serdes, Base64.Encoder encoder, Cipher RSAEncryptCipher, SecretKeyFactory secretKeyFactory, CipherSymmetricFactory cipherSymmetricFactory) { + this.serdes = serdes; + this.encoder = encoder; + this.RSAEncryptCipher = RSAEncryptCipher; + this.secretKeyFactory = secretKeyFactory; + this.cipherSymmetricFactory = cipherSymmetricFactory; + } + + public ByteArrayOutputStream JWEToCompact(JWE jwe) throws JsonToJwtException, CipherException, EncryptException { + + byte[] protectedHeader; + try { + protectedHeader = serdes.objectToByte(jwe.getHeader()); + } catch (JsonException e) { + throw new JsonToJwtException(HEADER_IS_INVALID, e); + } + + byte[] aad = encoder.encode(protectedHeader); + + + SecretKey cek; + try { + cek = secretKeyFactory.makeKey(KeyAlgorithm.AES); + } catch (SecretKeyException e) { + throw new EncryptException(FAILED_TO_CREATE_CONTENT_ENCRYPTION_KEY, e); + } + + Cipher symmetricCipher; + try { + symmetricCipher = symmetricCipherForEncrypt(cek, aad); + } catch (CipherException e) { + throw e; + } + + byte[] cipherTextWithAuthTag; + try { + cipherTextWithAuthTag = symmetricCipher.doFinal(jwe.getPayload()); + } catch (IllegalBlockSizeException e) { + throw new EncryptException(COULD_NOT_ENCRYPT, e); + } catch (BadPaddingException e) { + throw new EncryptException(COULD_NOT_ENCRYPT, e); + } + + byte[] encryptedKey; + try { + encryptedKey = RSAEncryptCipher.doFinal(cek.getEncoded()); + } catch (IllegalBlockSizeException e) { + throw new EncryptException(COULD_NOT_ENCRYPT_CEK, e); + } catch (BadPaddingException e) { + throw new EncryptException(COULD_NOT_ENCRYPT_CEK, e); + } + + byte[] initVector = symmetricCipher.getIV(); + byte[] cipherText = extractCipherText(cipherTextWithAuthTag); + byte[] authTag = extractAuthTag(cipherTextWithAuthTag); + + List jweParts = new ArrayList<>(); + jweParts.add(encoder.encode(protectedHeader)); + jweParts.add(encoder.encode(encryptedKey)); + jweParts.add(encoder.encode(initVector)); + jweParts.add(encoder.encode(cipherText)); + jweParts.add(encoder.encode(authTag)); + + return toCompact(jweParts); + } + + protected Cipher symmetricCipherForEncrypt(SecretKey cek, byte[] aad) throws CipherException { + Cipher cipher; + try { + cipher = cipherSymmetricFactory.forEncrypt(Transformation.AES_GCM_NO_PADDING, cek, aad); + } catch (CipherException e) { + throw e; + } + + return cipher; + } +} diff --git a/src/main/java/org/rootservices/jwt/jwk/KeyAlgorithm.java b/src/main/java/org/rootservices/jwt/jwk/KeyAlgorithm.java new file mode 100644 index 0000000..744162a --- /dev/null +++ b/src/main/java/org/rootservices/jwt/jwk/KeyAlgorithm.java @@ -0,0 +1,19 @@ +package org.rootservices.jwt.jwk; + +/** + * https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyGenerator + */ +public enum KeyAlgorithm { + AES ("AES"); + + private String value; + + KeyAlgorithm(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} + diff --git a/src/main/java/org/rootservices/jwt/jwk/PrivateKeyFactory.java b/src/main/java/org/rootservices/jwt/jwk/PrivateKeyFactory.java new file mode 100644 index 0000000..8126622 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/jwk/PrivateKeyFactory.java @@ -0,0 +1,55 @@ +package org.rootservices.jwt.jwk; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.rootservices.jwt.entity.jwk.RSAKeyPair; +import org.rootservices.jwt.jws.signer.factory.rsa.exception.PrivateKeyException; + +import java.security.KeyFactory; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.security.spec.RSAPrivateKeySpec; + + +public class PrivateKeyFactory { + private static final Logger LOGGER = LogManager.getLogger(PrivateKeyFactory.class); + public static final String PRIVATE_KEY_ERROR_MSG = "Could not make RSAPrivateCrtKey"; + private KeyFactory RSAKeyFactory; + + public PrivateKeyFactory(KeyFactory RSAKeyFactory) { + this.RSAKeyFactory = RSAKeyFactory; + } + + /** + * Returns a, RSAPrivateCrtKey, which is built from the input parameter, jwk. + * A RSAPrivateCrtKey is needed per, https://tools.ietf.org/html/rfc7517#section-9.3 + * + * @param jwk a RSAKeyPair + * @return an instance of RSAPrivateCrtKey + * @throws PrivateKeyException if jwk is invalid. + */ + public RSAPrivateCrtKey makePrivateKey(RSAKeyPair jwk) throws PrivateKeyException { + RSAPrivateKeySpec keySpec; + + keySpec = new RSAPrivateCrtKeySpec( + jwk.getN(), // modulus + jwk.getE(), // publicExponent + jwk.getD(), // privateExponent + jwk.getP(), // primeP + jwk.getQ(), // primeQ + jwk.getDp(), // primeExponentP + jwk.getDq(), // primeExponentQ + jwk.getQi() // crtCoefficient + ); + + RSAPrivateCrtKey privateKey; + try { + privateKey = (RSAPrivateCrtKey) RSAKeyFactory.generatePrivate(keySpec); + } catch (InvalidKeySpecException e) { + throw new PrivateKeyException(PRIVATE_KEY_ERROR_MSG, e); + } + + return privateKey; + } +} diff --git a/src/main/java/org/rootservices/jwt/jwk/PublicKeyFactory.java b/src/main/java/org/rootservices/jwt/jwk/PublicKeyFactory.java new file mode 100644 index 0000000..569e531 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/jwk/PublicKeyFactory.java @@ -0,0 +1,30 @@ +package org.rootservices.jwt.jwk; + +import org.rootservices.jwt.entity.jwk.RSAPublicKey; +import org.rootservices.jwt.jws.signer.factory.rsa.exception.PublicKeyException; + +import java.security.KeyFactory; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.RSAPublicKeySpec; + +public class PublicKeyFactory { + private KeyFactory RSAKeyFactory; + + public PublicKeyFactory(KeyFactory RSAKeyFactory) { + this.RSAKeyFactory = RSAKeyFactory; + } + + public java.security.interfaces.RSAPublicKey makePublicKey(RSAPublicKey jwk) throws PublicKeyException { + + RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(jwk.getN(), jwk.getE()); + java.security.interfaces.RSAPublicKey publicKey = null; + try { + publicKey = (java.security.interfaces.RSAPublicKey) RSAKeyFactory.generatePublic(rsaPublicKeySpec); + } catch (InvalidKeySpecException e) { + // will only reach here if there's something wrong with the RSAPublicKey + throw new PublicKeyException("Could not make java.security.interfaces.RSAPublicKey", e); + } + + return publicKey; + } +} diff --git a/src/main/java/org/rootservices/jwt/jwk/SecretKeyFactory.java b/src/main/java/org/rootservices/jwt/jwk/SecretKeyFactory.java new file mode 100644 index 0000000..cc92d55 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/jwk/SecretKeyFactory.java @@ -0,0 +1,28 @@ +package org.rootservices.jwt.jwk; + +import org.rootservices.jwt.jwk.exception.SecretKeyException; + +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import java.security.NoSuchAlgorithmException; + + +public class SecretKeyFactory { + public static final String MESSAGE = "Could not construct key generator"; + private static int keySize = 256; + + public SecretKey makeKey(KeyAlgorithm keyAlgorithm) throws SecretKeyException { + // docs say KeyGenerators can be reused as long as they use the same init values. + // Depending on the cost to create these this could be held onto for future use. + KeyGenerator keyGenerator = null; + try { + keyGenerator = KeyGenerator.getInstance(keyAlgorithm.getValue()); + } catch (NoSuchAlgorithmException e) { + throw new SecretKeyException(MESSAGE, e); + } + + keyGenerator.init(keySize); + + return keyGenerator.generateKey(); + } +} diff --git a/src/main/java/org/rootservices/jwt/jwk/exception/SecretKeyException.java b/src/main/java/org/rootservices/jwt/jwk/exception/SecretKeyException.java new file mode 100644 index 0000000..ae36b97 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/jwk/exception/SecretKeyException.java @@ -0,0 +1,7 @@ +package org.rootservices.jwt.jwk.exception; + +public class SecretKeyException extends Exception { + public SecretKeyException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/rootservices/jwt/jws/serialization/SecureJwtSerializer.java b/src/main/java/org/rootservices/jwt/jws/serialization/SecureJwtSerializer.java new file mode 100644 index 0000000..a1eb9b9 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/jws/serialization/SecureJwtSerializer.java @@ -0,0 +1,43 @@ +package org.rootservices.jwt.jws.serialization; + + +import org.rootservices.jwt.entity.jwt.Claims; +import org.rootservices.jwt.entity.jwt.JsonWebToken; +import org.rootservices.jwt.factory.SecureJwtFactory; +import org.rootservices.jwt.serialization.JwtSerde; +import org.rootservices.jwt.serialization.exception.JwtToJsonException; + +import java.io.ByteArrayOutputStream; + + +public class SecureJwtSerializer { + private SecureJwtFactory secureJwtFactory; + private JwtSerde jwtSerde; + + public SecureJwtSerializer(SecureJwtFactory secureJwtFactory, JwtSerde jwtSerde) { + this.secureJwtFactory = secureJwtFactory; + this.jwtSerde = jwtSerde; + } + + public String compactJwtToString(Claims claims) throws JwtToJsonException { + return compactJwt(claims).toString(); + } + + public ByteArrayOutputStream compactJwt(Claims claims) throws JwtToJsonException { + JsonWebToken jsonWebToken; + try { + jsonWebToken = secureJwtFactory.makeJwt(claims); + } catch (JwtToJsonException e) { + throw e; + } + + ByteArrayOutputStream compactJwt; + try { + compactJwt = jwtSerde.compactJwt(jsonWebToken); + } catch (JwtToJsonException e) { + throw e; + } + + return compactJwt; + } +} diff --git a/src/main/java/org/rootservices/jwt/jws/signer/MacSigner.java b/src/main/java/org/rootservices/jwt/jws/signer/MacSigner.java new file mode 100644 index 0000000..b044263 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/jws/signer/MacSigner.java @@ -0,0 +1,31 @@ +package org.rootservices.jwt.jws.signer; + + +import org.rootservices.jwt.serialization.JwtSerde; + +import javax.crypto.Mac; +import java.util.Base64.Encoder; + + +/** + * Created by tommackenzie on 8/19/15. + * + */ +public class MacSigner extends Signer { + private Mac mac; + + public MacSigner(JwtSerde jwtSerde, Mac mac, Encoder encoder) { + super(jwtSerde, encoder); + this.mac = mac; + } + + @Override + public byte[] run(byte[] input) { + return sign(input); + } + + private byte[] sign(byte[] input) { + byte[] signature = mac.doFinal(input); + return encode(signature); + } +} diff --git a/src/main/java/org/rootservices/jwt/signature/signer/RSASigner.java b/src/main/java/org/rootservices/jwt/jws/signer/RSASigner.java similarity index 62% rename from src/main/java/org/rootservices/jwt/signature/signer/RSASigner.java rename to src/main/java/org/rootservices/jwt/jws/signer/RSASigner.java index e57082a..8378d83 100644 --- a/src/main/java/org/rootservices/jwt/signature/signer/RSASigner.java +++ b/src/main/java/org/rootservices/jwt/jws/signer/RSASigner.java @@ -1,25 +1,22 @@ -package org.rootservices.jwt.signature.signer; +package org.rootservices.jwt.jws.signer; -import org.rootservices.jwt.serializer.JWTSerializer; -import org.rootservices.jwt.serializer.Serializer; +import org.rootservices.jwt.serialization.JwtSerde; import java.security.Signature; import java.security.SignatureException; import java.util.Base64.Encoder; -/** - * Created by tommackenzie on 11/3/15. - */ + public class RSASigner extends Signer { private Signature signature; - public RSASigner(Signature signature, JWTSerializer jwtSerializer, Encoder encoder) { - super(jwtSerializer, encoder); + public RSASigner(Signature signature, JwtSerde jwtSerde, Encoder encoder) { + super(jwtSerde, encoder); this.signature = signature; } @Override - public String run(byte[] input) { + public byte[] run(byte[] input) { try { signature.update(input); } catch (SignatureException e) { diff --git a/src/main/java/org/rootservices/jwt/signature/signer/SignAlgorithm.java b/src/main/java/org/rootservices/jwt/jws/signer/SignAlgorithm.java similarity index 94% rename from src/main/java/org/rootservices/jwt/signature/signer/SignAlgorithm.java rename to src/main/java/org/rootservices/jwt/jws/signer/SignAlgorithm.java index 1da4d3a..66c390e 100644 --- a/src/main/java/org/rootservices/jwt/signature/signer/SignAlgorithm.java +++ b/src/main/java/org/rootservices/jwt/jws/signer/SignAlgorithm.java @@ -1,4 +1,4 @@ -package org.rootservices.jwt.signature.signer; +package org.rootservices.jwt.jws.signer; import org.rootservices.jwt.entity.jwt.header.Algorithm; diff --git a/src/main/java/org/rootservices/jwt/jws/signer/Signer.java b/src/main/java/org/rootservices/jwt/jws/signer/Signer.java new file mode 100644 index 0000000..ae2dcaf --- /dev/null +++ b/src/main/java/org/rootservices/jwt/jws/signer/Signer.java @@ -0,0 +1,32 @@ +package org.rootservices.jwt.jws.signer; + +import org.rootservices.jwt.entity.jwt.JsonWebToken; +import org.rootservices.jwt.serialization.JwtSerde; +import org.rootservices.jwt.serialization.exception.JwtToJsonException; + +import java.nio.charset.Charset; +import java.util.Base64.Encoder; + +/** + * Created by tommackenzie on 8/19/15. + */ +public abstract class Signer { + private JwtSerde jwtSerde; + private Encoder encoder; + + public Signer(JwtSerde jwtSerde, Encoder encoder) { + this.jwtSerde = jwtSerde; + this.encoder = encoder; + } + + public byte[] run(JsonWebToken jwt) throws JwtToJsonException { + byte[] signInput = jwtSerde.makeSignInput(jwt.getHeader(), jwt.getClaims()); + return run(signInput); + } + + protected byte[] encode(byte[] input) { + return encoder.encode(input); + } + + public abstract byte[] run(byte[] input); +} diff --git a/src/main/java/org/rootservices/jwt/signature/signer/factory/SignerFactory.java b/src/main/java/org/rootservices/jwt/jws/signer/factory/SignerFactory.java similarity index 64% rename from src/main/java/org/rootservices/jwt/signature/signer/factory/SignerFactory.java rename to src/main/java/org/rootservices/jwt/jws/signer/factory/SignerFactory.java index 99ff6eb..d602ae7 100644 --- a/src/main/java/org/rootservices/jwt/signature/signer/factory/SignerFactory.java +++ b/src/main/java/org/rootservices/jwt/jws/signer/factory/SignerFactory.java @@ -1,22 +1,22 @@ -package org.rootservices.jwt.signature.signer.factory; +package org.rootservices.jwt.jws.signer.factory; import org.rootservices.jwt.entity.jwk.Key; import org.rootservices.jwt.entity.jwk.KeyType; import org.rootservices.jwt.entity.jwk.RSAKeyPair; import org.rootservices.jwt.entity.jwk.SymmetricKey; import org.rootservices.jwt.entity.jwt.header.Algorithm; -import org.rootservices.jwt.serializer.JWTSerializer; -import org.rootservices.jwt.signature.signer.MacSigner; -import org.rootservices.jwt.signature.signer.RSASigner; -import org.rootservices.jwt.signature.signer.SignAlgorithm; -import org.rootservices.jwt.signature.signer.Signer; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidAlgorithmException; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidJsonWebKeyException; -import org.rootservices.jwt.signature.signer.factory.hmac.MacFactory; -import org.rootservices.jwt.signature.signer.factory.hmac.exception.SecurityKeyException; -import org.rootservices.jwt.signature.signer.factory.rsa.PrivateKeySignatureFactory; -import org.rootservices.jwt.signature.signer.factory.rsa.exception.PrivateKeyException; -import org.rootservices.jwt.signature.signer.factory.rsa.exception.RSAPrivateKeyException; +import org.rootservices.jwt.serialization.JwtSerde; +import org.rootservices.jwt.jws.signer.MacSigner; +import org.rootservices.jwt.jws.signer.RSASigner; +import org.rootservices.jwt.jws.signer.SignAlgorithm; +import org.rootservices.jwt.jws.signer.Signer; +import org.rootservices.jwt.jws.signer.factory.exception.InvalidAlgorithmException; +import org.rootservices.jwt.jws.signer.factory.exception.InvalidJsonWebKeyException; +import org.rootservices.jwt.jws.signer.factory.hmac.MacFactory; +import org.rootservices.jwt.jws.signer.factory.hmac.exception.SecurityKeyException; +import org.rootservices.jwt.jws.signer.factory.rsa.PrivateKeySignatureFactory; +import org.rootservices.jwt.jws.signer.factory.rsa.exception.PrivateKeyException; +import org.rootservices.jwt.jws.signer.factory.rsa.exception.RSAPrivateKeyException; import javax.crypto.Mac; @@ -32,12 +32,12 @@ public class SignerFactory { private MacFactory macFactory; private PrivateKeySignatureFactory privateKeySignatureFactory; private Base64.Encoder encoder; - private JWTSerializer jwtSerializer; + private JwtSerde jwtSerde; - public SignerFactory(MacFactory macFactory, PrivateKeySignatureFactory privateKeySignatureFactory, JWTSerializer jwtSerializer, Base64.Encoder encoder){ + public SignerFactory(MacFactory macFactory, PrivateKeySignatureFactory privateKeySignatureFactory, JwtSerde jwtSerde, Base64.Encoder encoder){ this.macFactory = macFactory; this.privateKeySignatureFactory = privateKeySignatureFactory; - this.jwtSerializer = jwtSerializer; + this.jwtSerde = jwtSerde; this.encoder = encoder; } @@ -64,11 +64,11 @@ public Signer makeMacSigner(Algorithm alg, Key key) throws InvalidAlgorithmExcep throw e; } - return new MacSigner(jwtSerializer, mac, encoder); + return new MacSigner(jwtSerde, mac, encoder); } private Signer makeRSASigner(Algorithm alg, RSAKeyPair keyPair) throws InvalidAlgorithmException, InvalidJsonWebKeyException { - Signature signature = null; + Signature signature; SignAlgorithm signAlgorithm = SignAlgorithm.valueOf(alg.getValue()); @@ -81,6 +81,6 @@ private Signer makeRSASigner(Algorithm alg, RSAKeyPair keyPair) throws InvalidAl } catch (InvalidAlgorithmException e) { throw e; } - return new RSASigner(signature, jwtSerializer, encoder); + return new RSASigner(signature, jwtSerde, encoder); } } diff --git a/src/main/java/org/rootservices/jwt/signature/signer/factory/exception/InvalidAlgorithmException.java b/src/main/java/org/rootservices/jwt/jws/signer/factory/exception/InvalidAlgorithmException.java similarity index 77% rename from src/main/java/org/rootservices/jwt/signature/signer/factory/exception/InvalidAlgorithmException.java rename to src/main/java/org/rootservices/jwt/jws/signer/factory/exception/InvalidAlgorithmException.java index fd65881..c5aac3a 100644 --- a/src/main/java/org/rootservices/jwt/signature/signer/factory/exception/InvalidAlgorithmException.java +++ b/src/main/java/org/rootservices/jwt/jws/signer/factory/exception/InvalidAlgorithmException.java @@ -1,4 +1,4 @@ -package org.rootservices.jwt.signature.signer.factory.exception; +package org.rootservices.jwt.jws.signer.factory.exception; /** * Created by tommackenzie on 12/12/15. diff --git a/src/main/java/org/rootservices/jwt/signature/signer/factory/exception/InvalidJsonWebKeyException.java b/src/main/java/org/rootservices/jwt/jws/signer/factory/exception/InvalidJsonWebKeyException.java similarity index 77% rename from src/main/java/org/rootservices/jwt/signature/signer/factory/exception/InvalidJsonWebKeyException.java rename to src/main/java/org/rootservices/jwt/jws/signer/factory/exception/InvalidJsonWebKeyException.java index a844ac9..0b1110b 100644 --- a/src/main/java/org/rootservices/jwt/signature/signer/factory/exception/InvalidJsonWebKeyException.java +++ b/src/main/java/org/rootservices/jwt/jws/signer/factory/exception/InvalidJsonWebKeyException.java @@ -1,4 +1,4 @@ -package org.rootservices.jwt.signature.signer.factory.exception; +package org.rootservices.jwt.jws.signer.factory.exception; /** * Created by tommackenzie on 12/13/15. diff --git a/src/main/java/org/rootservices/jwt/signature/signer/factory/exception/SignerException.java b/src/main/java/org/rootservices/jwt/jws/signer/factory/exception/SignerException.java similarity index 75% rename from src/main/java/org/rootservices/jwt/signature/signer/factory/exception/SignerException.java rename to src/main/java/org/rootservices/jwt/jws/signer/factory/exception/SignerException.java index 19276cc..fe03649 100644 --- a/src/main/java/org/rootservices/jwt/signature/signer/factory/exception/SignerException.java +++ b/src/main/java/org/rootservices/jwt/jws/signer/factory/exception/SignerException.java @@ -1,4 +1,4 @@ -package org.rootservices.jwt.signature.signer.factory.exception; +package org.rootservices.jwt.jws.signer.factory.exception; /** * Created by tommackenzie on 12/6/15. diff --git a/src/main/java/org/rootservices/jwt/signature/signer/factory/hmac/MacFactory.java b/src/main/java/org/rootservices/jwt/jws/signer/factory/hmac/MacFactory.java similarity index 80% rename from src/main/java/org/rootservices/jwt/signature/signer/factory/hmac/MacFactory.java rename to src/main/java/org/rootservices/jwt/jws/signer/factory/hmac/MacFactory.java index 7e5a71c..97bee99 100644 --- a/src/main/java/org/rootservices/jwt/signature/signer/factory/hmac/MacFactory.java +++ b/src/main/java/org/rootservices/jwt/jws/signer/factory/hmac/MacFactory.java @@ -1,9 +1,9 @@ -package org.rootservices.jwt.signature.signer.factory.hmac; +package org.rootservices.jwt.jws.signer.factory.hmac; import org.rootservices.jwt.entity.jwk.SymmetricKey; -import org.rootservices.jwt.signature.signer.SignAlgorithm; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidAlgorithmException; -import org.rootservices.jwt.signature.signer.factory.hmac.exception.SecurityKeyException; +import org.rootservices.jwt.jws.signer.SignAlgorithm; +import org.rootservices.jwt.jws.signer.factory.exception.InvalidAlgorithmException; +import org.rootservices.jwt.jws.signer.factory.hmac.exception.SecurityKeyException; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; diff --git a/src/main/java/org/rootservices/jwt/signature/signer/factory/hmac/exception/SecurityKeyException.java b/src/main/java/org/rootservices/jwt/jws/signer/factory/hmac/exception/SecurityKeyException.java similarity index 80% rename from src/main/java/org/rootservices/jwt/signature/signer/factory/hmac/exception/SecurityKeyException.java rename to src/main/java/org/rootservices/jwt/jws/signer/factory/hmac/exception/SecurityKeyException.java index 70df18d..734aee0 100644 --- a/src/main/java/org/rootservices/jwt/signature/signer/factory/hmac/exception/SecurityKeyException.java +++ b/src/main/java/org/rootservices/jwt/jws/signer/factory/hmac/exception/SecurityKeyException.java @@ -1,4 +1,4 @@ -package org.rootservices.jwt.signature.signer.factory.hmac.exception; +package org.rootservices.jwt.jws.signer.factory.hmac.exception; /** * Created by tommackenzie on 12/13/15. diff --git a/src/main/java/org/rootservices/jwt/signature/signer/factory/rsa/PrivateKeySignatureFactory.java b/src/main/java/org/rootservices/jwt/jws/signer/factory/rsa/PrivateKeySignatureFactory.java similarity index 82% rename from src/main/java/org/rootservices/jwt/signature/signer/factory/rsa/PrivateKeySignatureFactory.java rename to src/main/java/org/rootservices/jwt/jws/signer/factory/rsa/PrivateKeySignatureFactory.java index f800c27..aa17c60 100644 --- a/src/main/java/org/rootservices/jwt/signature/signer/factory/rsa/PrivateKeySignatureFactory.java +++ b/src/main/java/org/rootservices/jwt/jws/signer/factory/rsa/PrivateKeySignatureFactory.java @@ -1,10 +1,10 @@ -package org.rootservices.jwt.signature.signer.factory.rsa; +package org.rootservices.jwt.jws.signer.factory.rsa; import org.rootservices.jwt.entity.jwk.RSAKeyPair; -import org.rootservices.jwt.signature.signer.SignAlgorithm; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidAlgorithmException; -import org.rootservices.jwt.signature.signer.factory.rsa.exception.PrivateKeyException; -import org.rootservices.jwt.signature.signer.factory.rsa.exception.RSAPrivateKeyException; +import org.rootservices.jwt.jws.signer.SignAlgorithm; +import org.rootservices.jwt.jws.signer.factory.exception.InvalidAlgorithmException; +import org.rootservices.jwt.jws.signer.factory.rsa.exception.PrivateKeyException; +import org.rootservices.jwt.jws.signer.factory.rsa.exception.RSAPrivateKeyException; import java.security.*; import java.security.interfaces.RSAPrivateCrtKey; @@ -28,8 +28,9 @@ public PrivateKeySignatureFactory(KeyFactory RSAKeyFactory) { * Returns a, RSAPrivateCrtKey, which is built from the input parameter, jwk. * A RSAPrivateCrtKey is needed per, https://tools.ietf.org/html/rfc7517#section-9.3 * - * @param jwk - * @return + * @param jwk a RSAKeyPair + * @return an instance of RSAPrivateCrtKey + * @throws PrivateKeyException if jwk is invalid. */ public RSAPrivateCrtKey makePrivateKey(RSAKeyPair jwk) throws PrivateKeyException { RSAPrivateKeySpec keySpec; diff --git a/src/main/java/org/rootservices/jwt/signature/signer/factory/rsa/PublicKeySignatureFactory.java b/src/main/java/org/rootservices/jwt/jws/signer/factory/rsa/PublicKeySignatureFactory.java similarity index 80% rename from src/main/java/org/rootservices/jwt/signature/signer/factory/rsa/PublicKeySignatureFactory.java rename to src/main/java/org/rootservices/jwt/jws/signer/factory/rsa/PublicKeySignatureFactory.java index cb4a89d..69ee629 100644 --- a/src/main/java/org/rootservices/jwt/signature/signer/factory/rsa/PublicKeySignatureFactory.java +++ b/src/main/java/org/rootservices/jwt/jws/signer/factory/rsa/PublicKeySignatureFactory.java @@ -1,11 +1,10 @@ -package org.rootservices.jwt.signature.signer.factory.rsa; +package org.rootservices.jwt.jws.signer.factory.rsa; import org.rootservices.jwt.entity.jwk.RSAPublicKey; -import org.rootservices.jwt.entity.jwt.header.Algorithm; -import org.rootservices.jwt.signature.signer.SignAlgorithm; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidAlgorithmException; -import org.rootservices.jwt.signature.signer.factory.rsa.exception.PublicKeyException; -import org.rootservices.jwt.signature.signer.factory.rsa.exception.RSAPublicKeyException; +import org.rootservices.jwt.jws.signer.SignAlgorithm; +import org.rootservices.jwt.jws.signer.factory.exception.InvalidAlgorithmException; +import org.rootservices.jwt.jws.signer.factory.rsa.exception.PublicKeyException; +import org.rootservices.jwt.jws.signer.factory.rsa.exception.RSAPublicKeyException; import java.security.*; import java.security.spec.InvalidKeySpecException; @@ -39,7 +38,7 @@ public java.security.interfaces.RSAPublicKey makePublicKey(RSAPublicKey jwk) thr public Signature makeSignature(SignAlgorithm alg, RSAPublicKey jwk) throws PublicKeyException, InvalidAlgorithmException, RSAPublicKeyException { java.security.interfaces.RSAPublicKey securityPublicKey = makePublicKey(jwk); - Signature signature = null; + Signature signature; try { signature = Signature.getInstance(alg.getJdkAlgorithm()); } catch (NoSuchAlgorithmException e) { diff --git a/src/main/java/org/rootservices/jwt/signature/signer/factory/rsa/exception/PrivateKeyException.java b/src/main/java/org/rootservices/jwt/jws/signer/factory/rsa/exception/PrivateKeyException.java similarity index 74% rename from src/main/java/org/rootservices/jwt/signature/signer/factory/rsa/exception/PrivateKeyException.java rename to src/main/java/org/rootservices/jwt/jws/signer/factory/rsa/exception/PrivateKeyException.java index 6cb124e..2e87e07 100644 --- a/src/main/java/org/rootservices/jwt/signature/signer/factory/rsa/exception/PrivateKeyException.java +++ b/src/main/java/org/rootservices/jwt/jws/signer/factory/rsa/exception/PrivateKeyException.java @@ -1,4 +1,4 @@ -package org.rootservices.jwt.signature.signer.factory.rsa.exception; +package org.rootservices.jwt.jws.signer.factory.rsa.exception; /** * Created by tommackenzie on 12/7/15. diff --git a/src/main/java/org/rootservices/jwt/signature/signer/factory/rsa/exception/PublicKeyException.java b/src/main/java/org/rootservices/jwt/jws/signer/factory/rsa/exception/PublicKeyException.java similarity index 74% rename from src/main/java/org/rootservices/jwt/signature/signer/factory/rsa/exception/PublicKeyException.java rename to src/main/java/org/rootservices/jwt/jws/signer/factory/rsa/exception/PublicKeyException.java index 40782ec..2e00433 100644 --- a/src/main/java/org/rootservices/jwt/signature/signer/factory/rsa/exception/PublicKeyException.java +++ b/src/main/java/org/rootservices/jwt/jws/signer/factory/rsa/exception/PublicKeyException.java @@ -1,4 +1,4 @@ -package org.rootservices.jwt.signature.signer.factory.rsa.exception; +package org.rootservices.jwt.jws.signer.factory.rsa.exception; /** * Created by tommackenzie on 12/7/15. diff --git a/src/main/java/org/rootservices/jwt/signature/signer/factory/rsa/exception/RSAPrivateKeyException.java b/src/main/java/org/rootservices/jwt/jws/signer/factory/rsa/exception/RSAPrivateKeyException.java similarity index 75% rename from src/main/java/org/rootservices/jwt/signature/signer/factory/rsa/exception/RSAPrivateKeyException.java rename to src/main/java/org/rootservices/jwt/jws/signer/factory/rsa/exception/RSAPrivateKeyException.java index 3e0fa7d..45c8048 100644 --- a/src/main/java/org/rootservices/jwt/signature/signer/factory/rsa/exception/RSAPrivateKeyException.java +++ b/src/main/java/org/rootservices/jwt/jws/signer/factory/rsa/exception/RSAPrivateKeyException.java @@ -1,4 +1,4 @@ -package org.rootservices.jwt.signature.signer.factory.rsa.exception; +package org.rootservices.jwt.jws.signer.factory.rsa.exception; /** * Created by tommackenzie on 12/13/15. diff --git a/src/main/java/org/rootservices/jwt/signature/signer/factory/rsa/exception/RSAPublicKeyException.java b/src/main/java/org/rootservices/jwt/jws/signer/factory/rsa/exception/RSAPublicKeyException.java similarity index 75% rename from src/main/java/org/rootservices/jwt/signature/signer/factory/rsa/exception/RSAPublicKeyException.java rename to src/main/java/org/rootservices/jwt/jws/signer/factory/rsa/exception/RSAPublicKeyException.java index e6d289e..6c7bc00 100644 --- a/src/main/java/org/rootservices/jwt/signature/signer/factory/rsa/exception/RSAPublicKeyException.java +++ b/src/main/java/org/rootservices/jwt/jws/signer/factory/rsa/exception/RSAPublicKeyException.java @@ -1,4 +1,4 @@ -package org.rootservices.jwt.signature.signer.factory.rsa.exception; +package org.rootservices.jwt.jws.signer.factory.rsa.exception; /** * Created by tommackenzie on 12/13/15. diff --git a/src/main/java/org/rootservices/jwt/signature/signer/factory/rsa/exception/SignatureException.java b/src/main/java/org/rootservices/jwt/jws/signer/factory/rsa/exception/SignatureException.java similarity index 74% rename from src/main/java/org/rootservices/jwt/signature/signer/factory/rsa/exception/SignatureException.java rename to src/main/java/org/rootservices/jwt/jws/signer/factory/rsa/exception/SignatureException.java index cf2b8e2..5a795fd 100644 --- a/src/main/java/org/rootservices/jwt/signature/signer/factory/rsa/exception/SignatureException.java +++ b/src/main/java/org/rootservices/jwt/jws/signer/factory/rsa/exception/SignatureException.java @@ -1,4 +1,4 @@ -package org.rootservices.jwt.signature.signer.factory.rsa.exception; +package org.rootservices.jwt.jws.signer.factory.rsa.exception; /** * Created by tommackenzie on 12/6/15. diff --git a/src/main/java/org/rootservices/jwt/signature/verifier/VerifyMacSignature.java b/src/main/java/org/rootservices/jwt/jws/verifier/VerifyMacSignature.java similarity index 65% rename from src/main/java/org/rootservices/jwt/signature/verifier/VerifyMacSignature.java rename to src/main/java/org/rootservices/jwt/jws/verifier/VerifyMacSignature.java index 12ac378..5e0edb4 100644 --- a/src/main/java/org/rootservices/jwt/signature/verifier/VerifyMacSignature.java +++ b/src/main/java/org/rootservices/jwt/jws/verifier/VerifyMacSignature.java @@ -1,13 +1,12 @@ -package org.rootservices.jwt.signature.verifier; +package org.rootservices.jwt.jws.verifier; import org.rootservices.jwt.entity.jwt.JsonWebToken; -import org.rootservices.jwt.signature.signer.Signer; +import org.rootservices.jwt.jws.signer.Signer; + +import java.util.Arrays; + -/** - * Created by tommackenzie on 8/26/15. - * - */ public class VerifyMacSignature extends VerifySignature { private Signer macSigner; @@ -18,14 +17,14 @@ public VerifyMacSignature(Signer macSigner) { @Override public boolean run(JsonWebToken token) { - String generatedSignature = ""; - String actualSignature = ""; + byte[] generatedSignature = null; + byte[] actualSignature = null; if ( token.getSignature().isPresent()) { byte[] input = createSignInput(token.getJwt().get()); generatedSignature = macSigner.run(input); actualSignature = token.getSignature().get(); } - return actualSignature.equals(generatedSignature); + return Arrays.equals(actualSignature, generatedSignature); } } diff --git a/src/main/java/org/rootservices/jwt/signature/verifier/VerifyRsaSignature.java b/src/main/java/org/rootservices/jwt/jws/verifier/VerifyRsaSignature.java similarity index 95% rename from src/main/java/org/rootservices/jwt/signature/verifier/VerifyRsaSignature.java rename to src/main/java/org/rootservices/jwt/jws/verifier/VerifyRsaSignature.java index 4314292..b023985 100644 --- a/src/main/java/org/rootservices/jwt/signature/verifier/VerifyRsaSignature.java +++ b/src/main/java/org/rootservices/jwt/jws/verifier/VerifyRsaSignature.java @@ -1,4 +1,4 @@ -package org.rootservices.jwt.signature.verifier; +package org.rootservices.jwt.jws.verifier; import org.rootservices.jwt.entity.jwt.JsonWebToken; diff --git a/src/main/java/org/rootservices/jwt/signature/verifier/VerifySignature.java b/src/main/java/org/rootservices/jwt/jws/verifier/VerifySignature.java similarity index 89% rename from src/main/java/org/rootservices/jwt/signature/verifier/VerifySignature.java rename to src/main/java/org/rootservices/jwt/jws/verifier/VerifySignature.java index 9c6eb6e..8afc717 100644 --- a/src/main/java/org/rootservices/jwt/signature/verifier/VerifySignature.java +++ b/src/main/java/org/rootservices/jwt/jws/verifier/VerifySignature.java @@ -1,4 +1,4 @@ -package org.rootservices.jwt.signature.verifier; +package org.rootservices.jwt.jws.verifier; import org.rootservices.jwt.entity.jwt.JsonWebToken; diff --git a/src/main/java/org/rootservices/jwt/signature/verifier/factory/VerifySignatureFactory.java b/src/main/java/org/rootservices/jwt/jws/verifier/factory/VerifySignatureFactory.java similarity index 51% rename from src/main/java/org/rootservices/jwt/signature/verifier/factory/VerifySignatureFactory.java rename to src/main/java/org/rootservices/jwt/jws/verifier/factory/VerifySignatureFactory.java index 993c600..65bf114 100644 --- a/src/main/java/org/rootservices/jwt/signature/verifier/factory/VerifySignatureFactory.java +++ b/src/main/java/org/rootservices/jwt/jws/verifier/factory/VerifySignatureFactory.java @@ -1,20 +1,21 @@ -package org.rootservices.jwt.signature.verifier.factory; +package org.rootservices.jwt.jws.verifier.factory; import org.rootservices.jwt.entity.jwk.Key; import org.rootservices.jwt.entity.jwk.KeyType; import org.rootservices.jwt.entity.jwk.RSAPublicKey; import org.rootservices.jwt.entity.jwt.header.Algorithm; -import org.rootservices.jwt.signature.signer.SignAlgorithm; -import org.rootservices.jwt.signature.signer.Signer; -import org.rootservices.jwt.signature.signer.factory.SignerFactory; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidAlgorithmException; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidJsonWebKeyException; -import org.rootservices.jwt.signature.signer.factory.rsa.PublicKeySignatureFactory; -import org.rootservices.jwt.signature.signer.factory.rsa.exception.PublicKeyException; -import org.rootservices.jwt.signature.signer.factory.rsa.exception.RSAPublicKeyException; -import org.rootservices.jwt.signature.verifier.VerifyMacSignature; -import org.rootservices.jwt.signature.verifier.VerifyRsaSignature; -import org.rootservices.jwt.signature.verifier.VerifySignature; +import org.rootservices.jwt.exception.SignatureException; +import org.rootservices.jwt.jws.signer.SignAlgorithm; +import org.rootservices.jwt.jws.signer.Signer; +import org.rootservices.jwt.jws.signer.factory.SignerFactory; +import org.rootservices.jwt.jws.signer.factory.exception.InvalidAlgorithmException; +import org.rootservices.jwt.jws.signer.factory.exception.InvalidJsonWebKeyException; +import org.rootservices.jwt.jws.signer.factory.rsa.PublicKeySignatureFactory; +import org.rootservices.jwt.jws.signer.factory.rsa.exception.PublicKeyException; +import org.rootservices.jwt.jws.signer.factory.rsa.exception.RSAPublicKeyException; +import org.rootservices.jwt.jws.verifier.VerifyMacSignature; +import org.rootservices.jwt.jws.verifier.VerifyRsaSignature; +import org.rootservices.jwt.jws.verifier.VerifySignature; import java.security.Signature; import java.util.Base64.Decoder; @@ -23,7 +24,8 @@ * Created by tommackenzie on 11/14/15. */ public class VerifySignatureFactory { - + public static final String ALG_WAS_INVALID = "Could not construct Signer. Algorithm was invalid."; + public static final String KEY_WAS_INVALID = "Could not construct Signer. Key was invalid."; private SignerFactory signerFactory; private PublicKeySignatureFactory publicKeySignatureFactory; private Decoder decoder; @@ -34,7 +36,7 @@ public VerifySignatureFactory(SignerFactory signerFactory, PublicKeySignatureFac this.decoder = decoder; } - public VerifySignature makeVerifySignature(Algorithm algorithm, Key key) throws InvalidAlgorithmException, InvalidJsonWebKeyException { + public VerifySignature makeVerifySignature(Algorithm algorithm, Key key) throws SignatureException { VerifySignature verifySignature = null; if (key.getKeyType() == KeyType.OCT) { @@ -45,12 +47,20 @@ public VerifySignature makeVerifySignature(Algorithm algorithm, Key key) throws return verifySignature; } - private VerifySignature makeVerifyMacSignature(Algorithm algorithm, Key key) throws InvalidAlgorithmException, InvalidJsonWebKeyException { - Signer macSigner = signerFactory.makeMacSigner(algorithm, key); + private VerifySignature makeVerifyMacSignature(Algorithm algorithm, Key key) throws SignatureException { + Signer macSigner; + try { + macSigner = signerFactory.makeMacSigner(algorithm, key); + } catch (InvalidAlgorithmException e) { + throw new SignatureException(ALG_WAS_INVALID, e); + } catch (InvalidJsonWebKeyException e) { + throw new SignatureException(KEY_WAS_INVALID, e); + } + return new VerifyMacSignature(macSigner); } - private VerifySignature makeVerifyRsaSignature(Algorithm algorithm, RSAPublicKey key) throws InvalidJsonWebKeyException, InvalidAlgorithmException { + private VerifySignature makeVerifyRsaSignature(Algorithm algorithm, RSAPublicKey key) throws SignatureException { Signature signature; SignAlgorithm signAlgorithm = SignAlgorithm.valueOf(algorithm.getValue()); @@ -58,11 +68,11 @@ private VerifySignature makeVerifyRsaSignature(Algorithm algorithm, RSAPublicKey try { signature = publicKeySignatureFactory.makeSignature(signAlgorithm, key); } catch (PublicKeyException e) { - throw new InvalidJsonWebKeyException("", e); + throw new SignatureException(KEY_WAS_INVALID, e); } catch (RSAPublicKeyException e) { - throw new InvalidJsonWebKeyException("", e); + throw new SignatureException(KEY_WAS_INVALID, e); } catch (InvalidAlgorithmException e) { - throw e; + throw new SignatureException(ALG_WAS_INVALID, e); } return new VerifyRsaSignature(signature, decoder); diff --git a/src/main/java/org/rootservices/jwt/serialization/HeaderDeserializer.java b/src/main/java/org/rootservices/jwt/serialization/HeaderDeserializer.java new file mode 100644 index 0000000..c42f223 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/serialization/HeaderDeserializer.java @@ -0,0 +1,41 @@ +package org.rootservices.jwt.serialization; + +import org.rootservices.jwt.entity.jwt.header.Header; +import org.rootservices.jwt.exception.InvalidJWT; +import org.rootservices.jwt.serialization.exception.JsonException; +import org.rootservices.jwt.serialization.exception.JsonToJwtException; + +import java.util.Base64; + +public class HeaderDeserializer { + public static final String JWT_SPLITTER = "\\."; + public static final String INVALID_HEADER = "JOSE Header is invalid"; + public static final String JWT_IS_NOT_SPLITTABLE = "JWT is not splittable by '.'"; + private Base64.Decoder decoder; + private Serdes serdes; + + public HeaderDeserializer(Base64.Decoder decoder, Serdes serdes) { + this.decoder = decoder; + this.serdes = serdes; + } + + public Header toHeader(String encodedJwt) throws JsonToJwtException, InvalidJWT { + String[] jwtParts = encodedJwt.split(JWT_SPLITTER); + + if (jwtParts.length == 0) { + throw new InvalidJWT(JWT_IS_NOT_SPLITTABLE); + } + + byte[] headerJson = decoder.decode(jwtParts[0]); + + Header header; + try { + header = (Header) serdes.jsonBytesToObject(headerJson, Header.class); + } catch (JsonException e) { + throw new JsonToJwtException(INVALID_HEADER, e); + } + + return header; + } + +} diff --git a/src/main/java/org/rootservices/jwt/serialization/JwtSerde.java b/src/main/java/org/rootservices/jwt/serialization/JwtSerde.java new file mode 100644 index 0000000..9e1ce9c --- /dev/null +++ b/src/main/java/org/rootservices/jwt/serialization/JwtSerde.java @@ -0,0 +1,180 @@ +package org.rootservices.jwt.serialization; + +import org.rootservices.jwt.entity.jwt.Claims; +import org.rootservices.jwt.entity.jwt.JsonWebToken; +import org.rootservices.jwt.entity.jwt.header.Header; +import org.rootservices.jwt.exception.InvalidJWT; +import org.rootservices.jwt.serialization.exception.JsonToJwtException; +import org.rootservices.jwt.serialization.exception.JsonException; +import org.rootservices.jwt.serialization.exception.JwtToJsonException; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import java.util.ArrayList; +import java.util.Base64.Encoder; +import java.util.Base64.Decoder; +import java.util.List; +import java.util.Optional; + + +/** + * A Serializer and Deserializer that converts: + * - a jwt as a string to a instance of a JsonWebToken. + * - a JsonWebToken to its string representation. + */ +public class JwtSerde { + public static final String JWT_SPLITTER = "\\."; + public static final String INVALID_JSON = "JWT json is invalid"; + public static final String COULD_NOT_SERIALIZE = "Could not make sign input"; + public static final String THIS_IS_A_JWE = "This is a JWE"; + public static final String TOO_MANY_MEMBERS = "Too many members"; + public static final String COULD_NOT_COMBINE_JWT_MEMBERS = "Could not combine jwt members"; + public static final String COULD_NOT_COMBINE_SIGN_INPUTS = "Could not combine sign inputs"; + public final int JWT_LENGTH = 2; + public final int JWS_LENGTH = 3; + public final int JWE_LENGTH = 5; + private Serdes serdes; + private Encoder encoder; + private Decoder decoder; + private final String DELIMITTER = "."; + private final byte[] DELIMITER = ".".getBytes(); + + public JwtSerde(Serdes serdes, Encoder encoder, Decoder decoder) { + this.serdes = serdes; + this.encoder = encoder; + this.decoder = decoder; + } + + public byte[] makeSignInput(Header header, Claims claims) throws JwtToJsonException { + + List members = membersForSigning(header, claims); + byte[] signInput; + + try { + signInput = compact(members, true).toByteArray(); + } catch (IOException e) { + throw new JwtToJsonException(COULD_NOT_COMBINE_SIGN_INPUTS, e); + } + + return signInput; + } + + protected List membersForSigning(Header header, Claims claims) throws JwtToJsonException { + List members = new ArrayList<>(); + byte[] headerJson; + byte[] claimsJson; + + try { + headerJson = serdes.objectToByte(header); + claimsJson = serdes.objectToByte(claims); + } catch (JsonException e) { + throw new JwtToJsonException(COULD_NOT_SERIALIZE, e); + } + + members.add(encoder.encode(headerJson)); + members.add(encoder.encode(claimsJson)); + return members; + } + + public ByteArrayOutputStream compactJwt(JsonWebToken jwt) throws JwtToJsonException { + + List members = membersForSigning(jwt.getHeader(), jwt.getClaims()); + + if (jwt.getSignature().isPresent()) + members.add(jwt.getSignature().get()); + + ByteArrayOutputStream compactJwt; + try { + compactJwt = compact(members, false); + } catch (IOException e) { + throw new JwtToJsonException(COULD_NOT_COMBINE_JWT_MEMBERS, e); + } + return compactJwt; + } + + public JsonWebToken stringToJwt(String jwtAsText, Class claimClass) throws JsonToJwtException, InvalidJWT { + String[] jwtParts = jwtAsText.split(JWT_SPLITTER); + JsonWebToken jwt; + + if (jwtParts.length == JWT_LENGTH) { + jwt = jwt(jwtParts, claimClass, jwtAsText); + } else if (jwtParts.length == JWS_LENGTH && jwtParts[JWS_LENGTH-1] != null) { + jwt = jws(jwtParts, claimClass, jwtAsText); + } else if (jwtParts.length == JWE_LENGTH) { + throw new InvalidJWT(THIS_IS_A_JWE); + } else { + throw new InvalidJWT(TOO_MANY_MEMBERS); + } + + return jwt; + } + + protected JsonWebToken jwt(String[] jwtParts, Class claimClass, String jwtAsText) throws JsonToJwtException { + byte[] headerJson = decoder.decode(jwtParts[0]); + byte[] claimsJson = decoder.decode(jwtParts[1]); + + Header header; + Claims claim; + try { + header = (Header) serdes.jsonBytesToObject(headerJson, Header.class); + claim = (Claims) serdes.jsonBytesToObject(claimsJson, claimClass); + } catch (JsonException e) { + throw new JsonToJwtException(INVALID_JSON, e); + } + + JsonWebToken jwt = new JsonWebToken(header, claim, Optional.of(jwtAsText)); + + return jwt; + } + + protected JsonWebToken jws(String[] jwsParts, Class claimClass, String jwtAsText) throws JsonToJwtException { + JsonWebToken jwt = jwt(jwsParts, claimClass, jwtAsText); + jwt.setSignature(Optional.of(jwsParts[JWS_LENGTH-1].getBytes())); + + return jwt; + } + + protected ByteArrayOutputStream compact(List members, Boolean forSigning) throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + for(int i=0; i < members.size(); i++) { + if (members.get(i) != null) { + try { + outputStream.write(members.get(i)); + } catch (IOException e) { + throw e; + } + } + if (shouldAppendDelimiter(i, members.size(), forSigning)) { + try { + outputStream.write(DELIMITER); + } catch (IOException e) { + throw e; + } + } + } + return outputStream; + } + + /** + * Deteremines if a "." should be appended to the current index of a compact jwt. + * + * When its not for signing + * + * Then a unsecure jwt will have a trailing "." + * Then a secure jwt (signed) will not have a trailing "." + * + * When its for signing + * Then a unsecure jwt will not have a trailing "." + * + * @param i the current index of the jwt + * @param numberOfMembers the number of members in the jwt + * @param forSigning is it being compacted to be signed. + * @return true if a "." should be appended. false if not. + */ + protected Boolean shouldAppendDelimiter(int i, int numberOfMembers, Boolean forSigning) { + return (i < numberOfMembers - 1 || (forSigning == false && i == numberOfMembers - 1 && i == 1)); + } + +} diff --git a/src/main/java/org/rootservices/jwt/serializer/Serializer.java b/src/main/java/org/rootservices/jwt/serialization/Serdes.java similarity index 53% rename from src/main/java/org/rootservices/jwt/serializer/Serializer.java rename to src/main/java/org/rootservices/jwt/serialization/Serdes.java index 8115cdb..70e4916 100644 --- a/src/main/java/org/rootservices/jwt/serializer/Serializer.java +++ b/src/main/java/org/rootservices/jwt/serialization/Serdes.java @@ -1,38 +1,35 @@ -package org.rootservices.jwt.serializer; +package org.rootservices.jwt.serialization; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.rootservices.jwt.serializer.exception.JsonException; +import org.rootservices.jwt.serialization.exception.JsonException; import java.io.IOException; /** - * Created by tommackenzie on 8/12/15. - * - * A Generic serializer that converts: - * - a object to json + * A Generic serializer and deserializer that converts: + * - an object to json * - json to a object * */ -public class Serializer { - +public class Serdes { + public static final String COULD_NOT_CREATE_JSON_FROM = "Could not create json from %s"; private ObjectMapper objectMapper; - public Serializer(ObjectMapper objectMapper) { + public Serdes(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } - - public String objectToJson(Object object) throws JsonException { + public byte[] objectToByte(Object object) throws JsonException { try { - return objectMapper.writeValueAsString(object); + return objectMapper.writeValueAsBytes(object); } catch (JsonProcessingException e) { - throw new JsonException("Could not create json from " + object.toString(), e); + throw new JsonException(String.format(COULD_NOT_CREATE_JSON_FROM ,object.toString()), e); } } public Object jsonBytesToObject(byte[] json, Class c) throws JsonException { - Object object = null; + Object object; try { object = objectMapper.readValue(json, c); } catch (IOException e) { diff --git a/src/main/java/org/rootservices/jwt/serialization/UnSecureJwtSerializer.java b/src/main/java/org/rootservices/jwt/serialization/UnSecureJwtSerializer.java new file mode 100644 index 0000000..4d8edf6 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/serialization/UnSecureJwtSerializer.java @@ -0,0 +1,37 @@ +package org.rootservices.jwt.serialization; + +import org.rootservices.jwt.entity.jwt.Claims; +import org.rootservices.jwt.entity.jwt.JsonWebToken; +import org.rootservices.jwt.factory.UnSecureJwtFactory; +import org.rootservices.jwt.serialization.exception.JwtToJsonException; + +import java.io.ByteArrayOutputStream; + + +public class UnSecureJwtSerializer { + private UnSecureJwtFactory unSecureJwtFactory; + private JwtSerde jwtSerde; + + public UnSecureJwtSerializer(UnSecureJwtFactory unSecureJwtFactory, JwtSerde jwtSerde) { + this.unSecureJwtFactory = unSecureJwtFactory; + this.jwtSerde = jwtSerde; + } + + public String compactJwtToString(Claims claims) { + return compactJwt(claims).toString(); + } + + public ByteArrayOutputStream compactJwt(Claims claims) { + + JsonWebToken jsonWebToken = unSecureJwtFactory.makeJwt(claims); + + ByteArrayOutputStream encodedJwt = null; + try { + encodedJwt = jwtSerde.compactJwt(jsonWebToken); + } catch (JwtToJsonException e) { + e.printStackTrace(); + } + + return encodedJwt; + } +} diff --git a/src/main/java/org/rootservices/jwt/serialization/exception/DecryptException.java b/src/main/java/org/rootservices/jwt/serialization/exception/DecryptException.java new file mode 100644 index 0000000..8bf295c --- /dev/null +++ b/src/main/java/org/rootservices/jwt/serialization/exception/DecryptException.java @@ -0,0 +1,7 @@ +package org.rootservices.jwt.serialization.exception; + +public class DecryptException extends Exception { + public DecryptException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/rootservices/jwt/serialization/exception/EncryptException.java b/src/main/java/org/rootservices/jwt/serialization/exception/EncryptException.java new file mode 100644 index 0000000..fe89091 --- /dev/null +++ b/src/main/java/org/rootservices/jwt/serialization/exception/EncryptException.java @@ -0,0 +1,7 @@ +package org.rootservices.jwt.serialization.exception; + +public class EncryptException extends Exception { + public EncryptException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/org/rootservices/jwt/serializer/exception/JsonException.java b/src/main/java/org/rootservices/jwt/serialization/exception/JsonException.java similarity index 78% rename from src/main/java/org/rootservices/jwt/serializer/exception/JsonException.java rename to src/main/java/org/rootservices/jwt/serialization/exception/JsonException.java index a4e434c..421d530 100644 --- a/src/main/java/org/rootservices/jwt/serializer/exception/JsonException.java +++ b/src/main/java/org/rootservices/jwt/serialization/exception/JsonException.java @@ -1,4 +1,4 @@ -package org.rootservices.jwt.serializer.exception; +package org.rootservices.jwt.serialization.exception; /** * Created by tommackenzie on 12/5/15. diff --git a/src/main/java/org/rootservices/jwt/serializer/exception/JsonToJwtException.java b/src/main/java/org/rootservices/jwt/serialization/exception/JsonToJwtException.java similarity index 83% rename from src/main/java/org/rootservices/jwt/serializer/exception/JsonToJwtException.java rename to src/main/java/org/rootservices/jwt/serialization/exception/JsonToJwtException.java index 4c58428..340ae4f 100644 --- a/src/main/java/org/rootservices/jwt/serializer/exception/JsonToJwtException.java +++ b/src/main/java/org/rootservices/jwt/serialization/exception/JsonToJwtException.java @@ -1,4 +1,4 @@ -package org.rootservices.jwt.serializer.exception; +package org.rootservices.jwt.serialization.exception; /** * Created by tommackenzie on 12/5/15. diff --git a/src/main/java/org/rootservices/jwt/serializer/exception/JwtToJsonException.java b/src/main/java/org/rootservices/jwt/serialization/exception/JwtToJsonException.java similarity index 83% rename from src/main/java/org/rootservices/jwt/serializer/exception/JwtToJsonException.java rename to src/main/java/org/rootservices/jwt/serialization/exception/JwtToJsonException.java index f7c3c71..41f4852 100644 --- a/src/main/java/org/rootservices/jwt/serializer/exception/JwtToJsonException.java +++ b/src/main/java/org/rootservices/jwt/serialization/exception/JwtToJsonException.java @@ -1,4 +1,4 @@ -package org.rootservices.jwt.serializer.exception; +package org.rootservices.jwt.serialization.exception; /** * Created by tommackenzie on 12/12/15. diff --git a/src/main/java/org/rootservices/jwt/serializer/JWTSerializer.java b/src/main/java/org/rootservices/jwt/serializer/JWTSerializer.java deleted file mode 100644 index 1d08294..0000000 --- a/src/main/java/org/rootservices/jwt/serializer/JWTSerializer.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.rootservices.jwt.serializer; - -import org.rootservices.jwt.entity.jwt.Claims; -import org.rootservices.jwt.entity.jwt.JsonWebToken; -import org.rootservices.jwt.entity.jwt.header.Header; -import org.rootservices.jwt.serializer.exception.JsonToJwtException; -import org.rootservices.jwt.serializer.exception.JsonException; -import org.rootservices.jwt.serializer.exception.JwtToJsonException; - -import java.nio.charset.Charset; - -import java.util.Base64.Encoder; -import java.util.Base64.Decoder; -import java.util.Optional; - -/** - * Created by tommackenzie on 8/13/15. - * - * A Serializer that converts: - * - a jwt as a string to a instance of a JsonWebToken. - * - a JsonWebToken to its string representation. - */ -public class JWTSerializer { - private final int SECURE_TOKEN_LENGTH = 3; - private Serializer serializer; - private Encoder encoder; - private Decoder decoder; - private final String DELIMITTER = "."; - - public JWTSerializer(Serializer serializer, Encoder encoder, Decoder decoder) { - this.serializer = serializer; - this.encoder = encoder; - this.decoder = decoder; - } - - public String makeSignInput(Header header, Claims claims) throws JwtToJsonException { - - String headerJson = ""; - String claimsJson = ""; - - try { - headerJson = serializer.objectToJson(header); - claimsJson = serializer.objectToJson(claims); - } catch (JsonException e) { - throw new JwtToJsonException("Could not make sign input", e); - } - - return encode(headerJson) + DELIMITTER + encode(claimsJson); - } - - public String jwtToString(JsonWebToken jwt) throws JwtToJsonException { - - String jwtAsText = makeSignInput(jwt.getHeader(), jwt.getClaims()) + DELIMITTER; - - if (jwt.getSignature().isPresent()) - jwtAsText+= jwt.getSignature().get(); - - return jwtAsText; - } - - private String encode(String input) { - return encoder.encodeToString(input.getBytes(Charset.forName("UTF-8"))); - } - - public JsonWebToken stringToJwt(String jwtAsText, Class claimClass) throws JsonToJwtException { - String[] jwtParts = jwtAsText.split("\\."); - - byte[] headerJson = decoder.decode(jwtParts[0]); - byte[] claimsJson = decoder.decode(jwtParts[1]); - - Header header = null; - Claims claim = null; - try { - header = (Header) serializer.jsonBytesToObject(headerJson, Header.class); - claim = (Claims) serializer.jsonBytesToObject(claimsJson, claimClass); - } catch (JsonException e) { - throw new JsonToJwtException("JWT json is invalid", e); - } - - JsonWebToken jwt = new JsonWebToken(header, claim, Optional.of(jwtAsText)); - - if (jwtParts.length == SECURE_TOKEN_LENGTH && jwtParts[SECURE_TOKEN_LENGTH-1] != null) - jwt.setSignature(Optional.of(jwtParts[SECURE_TOKEN_LENGTH-1])); - - return jwt; - } -} diff --git a/src/main/java/org/rootservices/jwt/signature/signer/MacSigner.java b/src/main/java/org/rootservices/jwt/signature/signer/MacSigner.java deleted file mode 100644 index eb60b41..0000000 --- a/src/main/java/org/rootservices/jwt/signature/signer/MacSigner.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.rootservices.jwt.signature.signer; - - -import org.rootservices.jwt.serializer.JWTSerializer; -import org.rootservices.jwt.serializer.Serializer; - -import javax.crypto.Mac; -import java.util.Base64.Encoder; - - -/** - * Created by tommackenzie on 8/19/15. - * - */ -public class MacSigner extends Signer { - private Mac mac; - - public MacSigner(JWTSerializer jwtSerializer, Mac mac, Encoder encoder) { - super(jwtSerializer, encoder); - this.mac = mac; - } - - @Override - public String run(byte[] input) { - return sign(input); - } - - private String sign(byte[] input) { - byte[] signature = mac.doFinal(input); - return encode(signature); - } -} diff --git a/src/main/java/org/rootservices/jwt/signature/signer/Signer.java b/src/main/java/org/rootservices/jwt/signature/signer/Signer.java deleted file mode 100644 index c340714..0000000 --- a/src/main/java/org/rootservices/jwt/signature/signer/Signer.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.rootservices.jwt.signature.signer; - -import org.rootservices.jwt.entity.jwt.JsonWebToken; -import org.rootservices.jwt.serializer.JWTSerializer; -import org.rootservices.jwt.serializer.exception.JwtToJsonException; - -import java.nio.charset.Charset; -import java.util.Base64.Encoder; - -/** - * Created by tommackenzie on 8/19/15. - */ -public abstract class Signer { - private JWTSerializer jwtSerializer; - private Encoder encoder; - - public Signer(JWTSerializer jwtSerializer, Encoder encoder) { - this.jwtSerializer = jwtSerializer; - this.encoder = encoder; - } - - private String encode(String input) { - return encode(input.getBytes(Charset.forName("UTF-8"))); - } - - public String run(JsonWebToken jwt) throws JwtToJsonException { - String signInput = jwtSerializer.makeSignInput(jwt.getHeader(), jwt.getClaims()); - return run(signInput.getBytes()); - } - - protected String encode(byte[] input) { - return encoder.encodeToString(input); - } - - public abstract String run(byte[] input); -} diff --git a/src/main/java/org/rootservices/jwt/translator/CSRToRSAPublicKey.java b/src/main/java/org/rootservices/jwt/translator/CSRToRSAPublicKey.java deleted file mode 100644 index d3538ae..0000000 --- a/src/main/java/org/rootservices/jwt/translator/CSRToRSAPublicKey.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.rootservices.jwt.translator; - -import org.bouncycastle.openssl.PEMParser; -import org.bouncycastle.pkcs.PKCS10CertificationRequest; -import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest; -import org.rootservices.jwt.entity.jwk.KeyType; -import org.rootservices.jwt.entity.jwk.RSAPublicKey; -import org.rootservices.jwt.entity.jwk.Use; -import org.rootservices.jwt.translator.exception.InvalidKeyException; -import org.rootservices.jwt.translator.exception.InvalidCsrException; - -import java.io.FileReader; -import java.io.IOException; -import java.security.NoSuchAlgorithmException; -import java.util.Optional; - -/** - * Created by tommackenzie on 12/1/15. - */ -public class CSRToRSAPublicKey { - - public RSAPublicKey translate(FileReader csr, Optional keyId, Use use) throws InvalidCsrException, InvalidKeyException { - - PEMParser pemParser = new PEMParser(csr); - PKCS10CertificationRequest certRequest = null; - try { - certRequest = (PKCS10CertificationRequest) pemParser.readObject(); - } catch (IOException e) { - throw new InvalidCsrException("invalid file reader", e); - } catch (ClassCastException e) { - throw new InvalidCsrException("csr file is not a valid csr", e); - } - - if (certRequest == null) { - throw new InvalidCsrException("Could not parse the file reader"); - } - - JcaPKCS10CertificationRequest jcaPKCS10CertificationRequest = new JcaPKCS10CertificationRequest(certRequest); - - java.security.interfaces.RSAPublicKey publicKey = null; - try { - publicKey = (java.security.interfaces.RSAPublicKey) jcaPKCS10CertificationRequest.getPublicKey(); - } catch (java.security.InvalidKeyException e) { - throw new InvalidKeyException("RSA public key from pem file is invalid", e); - } catch (NoSuchAlgorithmException e) { - throw new InvalidKeyException("Could not create RSA public key", e); - } - - return new RSAPublicKey( - keyId, - KeyType.RSA, - use, - publicKey.getModulus(), - publicKey.getPublicExponent() - ); - } - -} diff --git a/src/main/java/org/rootservices/jwt/translator/PemToRSAKeyPair.java b/src/main/java/org/rootservices/jwt/translator/PemToRSAKeyPair.java deleted file mode 100644 index d13625b..0000000 --- a/src/main/java/org/rootservices/jwt/translator/PemToRSAKeyPair.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.rootservices.jwt.translator; - -import org.bouncycastle.openssl.PEMException; -import org.bouncycastle.openssl.PEMKeyPair; -import org.bouncycastle.openssl.PEMParser; -import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; -import org.rootservices.jwt.entity.jwk.KeyType; -import org.rootservices.jwt.entity.jwk.RSAKeyPair; -import org.rootservices.jwt.entity.jwk.Use; -import org.rootservices.jwt.translator.exception.InvalidKeyException; -import org.rootservices.jwt.translator.exception.InvalidPemException; - -import java.io.FileReader; -import java.io.IOException; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.RSAPrivateCrtKeySpec; -import java.util.Optional; - -/** - * Created by tommackenzie on 11/30/15. - */ -public class PemToRSAKeyPair { - - private JcaPEMKeyConverter converter; - private KeyFactory RSAKeyFactory; - - public PemToRSAKeyPair(JcaPEMKeyConverter converter, KeyFactory RSAKeyFactory) { - this.converter = converter; - this.RSAKeyFactory = RSAKeyFactory; - } - - - public RSAKeyPair translate(FileReader pemFileReader, Optional keyId, Use use) throws InvalidPemException, InvalidKeyException { - PEMParser pemParser = new PEMParser(pemFileReader); - - PEMKeyPair pemKeyPair = null; - try { - pemKeyPair = (PEMKeyPair) pemParser.readObject(); - } catch (IOException e) { - throw new InvalidPemException("invalid file reader", e); - } catch (ClassCastException e) { - throw new InvalidPemException("pem did not not have a key pair", e); - } - - if (pemKeyPair == null) { - throw new InvalidPemException("Could not parse the file reader"); - } - - KeyPair keyPair = null; - try { - keyPair = converter.getKeyPair(pemKeyPair); - } catch (PEMException e) { - throw new InvalidPemException("Could not translate PEMKeyPair to a KeyPair"); - } - - RSAPrivateCrtKeySpec privateKey = null; - try { - privateKey = RSAKeyFactory.getKeySpec(keyPair.getPrivate(), RSAPrivateCrtKeySpec.class); - } catch (InvalidKeySpecException e) { - throw new InvalidKeyException("Could not create RSAPrivateCrtKeySpec", e); - } - - RSAKeyPair rsaKeyPair = new RSAKeyPair( - keyId, - KeyType.RSA, - use, - privateKey.getModulus(), - privateKey.getPublicExponent(), - privateKey.getPrivateExponent(), - privateKey.getPrimeP(), - privateKey.getPrimeQ(), - privateKey.getPrimeExponentP(), - privateKey.getPrimeExponentQ(), - privateKey.getCrtCoefficient() - ); - - return rsaKeyPair; - } -} diff --git a/src/main/java/org/rootservices/jwt/translator/exception/InvalidCsrException.java b/src/main/java/org/rootservices/jwt/translator/exception/InvalidCsrException.java deleted file mode 100644 index 4b8a5ee..0000000 --- a/src/main/java/org/rootservices/jwt/translator/exception/InvalidCsrException.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.rootservices.jwt.translator.exception; - -/** - * Created by tommackenzie on 12/8/15. - */ -public class InvalidCsrException extends Exception { - public InvalidCsrException(String message) { - super(message); - } - - public InvalidCsrException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/src/main/java/org/rootservices/jwt/translator/exception/InvalidKeyException.java b/src/main/java/org/rootservices/jwt/translator/exception/InvalidKeyException.java deleted file mode 100644 index c3e8216..0000000 --- a/src/main/java/org/rootservices/jwt/translator/exception/InvalidKeyException.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.rootservices.jwt.translator.exception; - -/** - * Created by tommackenzie on 12/8/15. - */ -public class InvalidKeyException extends Exception { - public InvalidKeyException(String message) { - super(message); - } - - public InvalidKeyException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/src/main/java/org/rootservices/jwt/translator/exception/InvalidPemException.java b/src/main/java/org/rootservices/jwt/translator/exception/InvalidPemException.java deleted file mode 100644 index c8bc63f..0000000 --- a/src/main/java/org/rootservices/jwt/translator/exception/InvalidPemException.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.rootservices.jwt.translator.exception; - -/** - * Created by tommackenzie on 12/8/15. - */ -public class InvalidPemException extends Exception { - public InvalidPemException(String message) { - super(message); - } - - public InvalidPemException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/src/test/java/examples/AsymmetricSignedJsonWebToken.java b/src/test/java/examples/AsymmetricSignedJsonWebToken.java index bd1f062..c271620 100644 --- a/src/test/java/examples/AsymmetricSignedJsonWebToken.java +++ b/src/test/java/examples/AsymmetricSignedJsonWebToken.java @@ -1,21 +1,19 @@ package examples; import helper.entity.Claim; -import org.rootservices.jwt.SecureJwtEncoder; -import org.rootservices.jwt.factory.SecureJwtFactory; -import org.rootservices.jwt.config.AppFactory; +import org.rootservices.jwt.jws.serialization.SecureJwtSerializer; +import org.rootservices.jwt.config.JwtAppFactory; import org.rootservices.jwt.entity.jwk.KeyType; import org.rootservices.jwt.entity.jwk.RSAKeyPair; import org.rootservices.jwt.entity.jwk.RSAPublicKey; import org.rootservices.jwt.entity.jwk.Use; import org.rootservices.jwt.entity.jwt.JsonWebToken; import org.rootservices.jwt.entity.jwt.header.Algorithm; -import org.rootservices.jwt.serializer.JWTSerializer; -import org.rootservices.jwt.serializer.exception.JsonToJwtException; -import org.rootservices.jwt.serializer.exception.JwtToJsonException; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidAlgorithmException; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidJsonWebKeyException; -import org.rootservices.jwt.signature.verifier.VerifySignature; +import org.rootservices.jwt.exception.SignatureException; +import org.rootservices.jwt.serialization.JwtSerde; +import org.rootservices.jwt.serialization.exception.JsonToJwtException; +import org.rootservices.jwt.serialization.exception.JwtToJsonException; +import org.rootservices.jwt.jws.verifier.VerifySignature; import java.math.BigInteger; import java.util.Optional; @@ -25,7 +23,7 @@ */ public class AsymmetricSignedJsonWebToken { - public String toEncodedJwt() { + public String toCompactJwt() { RSAKeyPair keyPair = new RSAKeyPair( Optional.of("test-key-id"), @@ -44,19 +42,17 @@ public String toEncodedJwt() { Claim claim = new Claim(); claim.setUriIsRoot(true); - AppFactory appFactory = new AppFactory(); - SecureJwtEncoder secureJwtEncoder = null; + JwtAppFactory appFactory = new JwtAppFactory(); + SecureJwtSerializer secureJwtSerializer = null; try { - secureJwtEncoder = appFactory.secureJwtEncoder(Algorithm.RS256, keyPair); - } catch (InvalidAlgorithmException e) { - e.printStackTrace(); - } catch (InvalidJsonWebKeyException e) { + secureJwtSerializer = appFactory.secureJwtSerializer(Algorithm.RS256, keyPair); + } catch (SignatureException e) { e.printStackTrace(); } String encodedJwt = null; try { - encodedJwt = secureJwtEncoder.encode(claim); + encodedJwt = secureJwtSerializer.compactJwtToString(claim); } catch (JwtToJsonException e) { e.printStackTrace(); } @@ -64,7 +60,7 @@ public String toEncodedJwt() { return encodedJwt; } - public Boolean verifySignature() throws JsonToJwtException, InvalidAlgorithmException, InvalidJsonWebKeyException { + public Boolean verifySignature() throws Exception { String jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJodHRwOi8vZXhhbXBsZS5jb20vaXNfcm9vdCI6dHJ1ZX0.ZaZoTp-lb3C7Sb7BKQm3BZyGiMxtehBtAeN9anuDPgO_F3eR8o9UU4c1RgCFDLqO_Ftg6QCmoZ1SEDuNw8AskJWSqcuJwcOttrqf46BHB89QuGtfmhEb5fIbyuqD-n2XM2hHhvPL6yJvLd3VQNvW2VexSL3fmutC5MYoPa8IfvjGZ_QKMwA7BBwcm4Djnnlu9HwiNg3a_y6-JJxr_jW5GD8VomHZbLasokR6h5N-y-DXIIYL3-oMl-_rE1BPdm_gE76p4Lo49BM-AyUxbShAHDl-EBKsz_Vo-Pgk_4rXkBOMMJQI95FrK5FeJs2yZxMoZ_V_f5_VGnXYNzq3SFJwnQ"; RSAPublicKey publicKey = new RSAPublicKey( @@ -75,23 +71,21 @@ public Boolean verifySignature() throws JsonToJwtException, InvalidAlgorithmExce new BigInteger("65537") ); - AppFactory appFactory = new AppFactory(); - JWTSerializer jwtSerializer = appFactory.jwtSerializer(); - JsonWebToken jsonWebToken = null; + JwtAppFactory appFactory = new JwtAppFactory(); + JwtSerde jwtSerde = appFactory.jwtSerde(); + JsonWebToken jsonWebToken; try { - jsonWebToken = jwtSerializer.stringToJwt(jwt, Claim.class); + jsonWebToken = jwtSerde.stringToJwt(jwt, Claim.class); } catch (JsonToJwtException e) { // could not serialize JsonWebToken to json string throw e; } - VerifySignature verifySignature = null; + VerifySignature verifySignature; try { verifySignature = appFactory.verifySignature(Algorithm.RS256, publicKey); - } catch (InvalidJsonWebKeyException e) { - throw e; - } catch (InvalidAlgorithmException e) { + } catch (SignatureException e) { throw e; } diff --git a/src/test/java/examples/CSRFileToRSAPublicKey.java b/src/test/java/examples/CSRFileToRSAPublicKey.java deleted file mode 100644 index 24e2637..0000000 --- a/src/test/java/examples/CSRFileToRSAPublicKey.java +++ /dev/null @@ -1,53 +0,0 @@ -package examples; - -import org.rootservices.jwt.config.AppFactory; -import org.rootservices.jwt.entity.jwk.RSAPublicKey; -import org.rootservices.jwt.entity.jwk.Use; -import org.rootservices.jwt.translator.CSRToRSAPublicKey; -import org.rootservices.jwt.translator.exception.InvalidCsrException; -import org.rootservices.jwt.translator.exception.InvalidKeyException; - -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Optional; - -/** - * Created by tommackenzie on 12/12/15. - */ -public class CSRFileToRSAPublicKey { - - public RSAPublicKey toRSAPublicKey() throws MalformedURLException, FileNotFoundException, InvalidCsrException, InvalidKeyException { - AppFactory appFactory = new AppFactory(); - CSRToRSAPublicKey csrToRSAPublicKey = appFactory.csrToRSAPublicKey(); - - URL privateKeyURL = null; - try { - privateKeyURL = new URL("file:///example/rsa-cert.csr"); - } catch (MalformedURLException e) { - // invalid url. - throw e; - } - - FileReader fr = null; - try { - fr = new FileReader(privateKeyURL.getFile()); - } catch (FileNotFoundException e) { - throw e; - } - - RSAPublicKey rsaPublicKey = null; - try { - rsaPublicKey = csrToRSAPublicKey.translate(fr, Optional.of("test-key-id"), Use.SIGNATURE); - } catch (InvalidCsrException e) { - // csr file could not be used. - throw e; - } catch (InvalidKeyException e) { - // key in the csr file could not be used. - throw e; - } - - return rsaPublicKey; - } -} diff --git a/src/test/java/examples/PemFileToRSAKeyPair.java b/src/test/java/examples/PemFileToRSAKeyPair.java deleted file mode 100644 index a136f55..0000000 --- a/src/test/java/examples/PemFileToRSAKeyPair.java +++ /dev/null @@ -1,53 +0,0 @@ -package examples; - -import org.rootservices.jwt.config.AppFactory; -import org.rootservices.jwt.entity.jwk.RSAKeyPair; -import org.rootservices.jwt.entity.jwk.Use; -import org.rootservices.jwt.translator.PemToRSAKeyPair; -import org.rootservices.jwt.translator.exception.InvalidKeyException; -import org.rootservices.jwt.translator.exception.InvalidPemException; - -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Optional; - -/** - * Created by tommackenzie on 12/12/15. - */ -public class PemFileToRSAKeyPair { - - public RSAKeyPair makeRSAKeyPair() throws MalformedURLException, FileNotFoundException, InvalidPemException, InvalidKeyException { - AppFactory appFactory = new AppFactory(); - PemToRSAKeyPair pemToRSAKeyPair = appFactory.pemToRSAKeyPair(); - - URL privateKeyURL = null; - try { - privateKeyURL = new URL("file:///example/rsa-private-key.pem"); - } catch (MalformedURLException e) { - // invalid url. - throw e; - } - - FileReader pemFileReader = null; - try { - pemFileReader = new FileReader(privateKeyURL.getFile()); - } catch (FileNotFoundException e) { - throw e; - } - - RSAKeyPair rsaKeyPair = null; - try { - rsaKeyPair = pemToRSAKeyPair.translate(pemFileReader, Optional.of("test-key-id"), Use.SIGNATURE); - } catch (InvalidPemException e) { - // pem file could not be used. - throw e; - } catch (InvalidKeyException e) { - // key in pem file could not be used. - throw e; - } - - return rsaKeyPair; - } -} diff --git a/src/test/java/examples/SymmetricSignedJsonWebToken.java b/src/test/java/examples/SymmetricSignedJsonWebToken.java index d096e2b..6666b47 100644 --- a/src/test/java/examples/SymmetricSignedJsonWebToken.java +++ b/src/test/java/examples/SymmetricSignedJsonWebToken.java @@ -1,19 +1,17 @@ package examples; import helper.entity.Claim; -import org.rootservices.jwt.SecureJwtEncoder; -import org.rootservices.jwt.factory.SecureJwtFactory; -import org.rootservices.jwt.config.AppFactory; +import org.rootservices.jwt.jws.serialization.SecureJwtSerializer; +import org.rootservices.jwt.config.JwtAppFactory; import org.rootservices.jwt.entity.jwk.SymmetricKey; import org.rootservices.jwt.entity.jwk.Use; import org.rootservices.jwt.entity.jwt.JsonWebToken; import org.rootservices.jwt.entity.jwt.header.Algorithm; -import org.rootservices.jwt.serializer.JWTSerializer; -import org.rootservices.jwt.serializer.exception.JsonToJwtException; -import org.rootservices.jwt.serializer.exception.JwtToJsonException; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidAlgorithmException; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidJsonWebKeyException; -import org.rootservices.jwt.signature.verifier.VerifySignature; +import org.rootservices.jwt.exception.SignatureException; +import org.rootservices.jwt.serialization.JwtSerde; +import org.rootservices.jwt.serialization.exception.JsonToJwtException; +import org.rootservices.jwt.serialization.exception.JwtToJsonException; +import org.rootservices.jwt.jws.verifier.VerifySignature; import java.util.Optional; @@ -22,9 +20,9 @@ */ public class SymmetricSignedJsonWebToken { - public String toEncodedJwt() { + public String tocCompactJwt() { - AppFactory appFactory = new AppFactory(); + JwtAppFactory appFactory = new JwtAppFactory(); SymmetricKey key = new SymmetricKey( Optional.of("test-key-id"), @@ -35,18 +33,16 @@ public String toEncodedJwt() { Claim claim = new Claim(); claim.setUriIsRoot(true); - SecureJwtEncoder secureJwtEncoder = null; + SecureJwtSerializer secureJwtSerializer = null; try { - secureJwtEncoder = appFactory.secureJwtEncoder(Algorithm.HS256, key); - } catch (InvalidAlgorithmException e) { - e.printStackTrace(); - } catch (InvalidJsonWebKeyException e) { + secureJwtSerializer = appFactory.secureJwtSerializer(Algorithm.HS256, key); + } catch (SignatureException e) { e.printStackTrace(); } String encodedJwt = null; try { - encodedJwt = secureJwtEncoder.encode(claim); + encodedJwt = secureJwtSerializer.compactJwtToString(claim); } catch (JwtToJsonException e) { e.printStackTrace(); } @@ -54,16 +50,16 @@ public String toEncodedJwt() { return encodedJwt; } - public Boolean verifySignature() throws JsonToJwtException, InvalidJsonWebKeyException, InvalidAlgorithmException { + public Boolean verifySignature() throws Exception { - AppFactory appFactory = new AppFactory(); + JwtAppFactory appFactory = new JwtAppFactory(); String jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJodHRwOi8vZXhhbXBsZS5jb20vaXNfcm9vdCI6dHJ1ZX0.TeZ3DKSE-gplbaoA8CK_RMojt8CfA1MTYaM_ZuOeGNw"; - JWTSerializer jwtSerializer = appFactory.jwtSerializer(); + JwtSerde jwtSerde = appFactory.jwtSerde(); JsonWebToken jsonWebToken = null; try { - jsonWebToken = jwtSerializer.stringToJwt(jwt, Claim.class); + jsonWebToken = jwtSerde.stringToJwt(jwt, Claim.class); } catch (JsonToJwtException e) { // could not create a JsonWebToken from the jwt json. throw e; @@ -79,9 +75,7 @@ public Boolean verifySignature() throws JsonToJwtException, InvalidJsonWebKeyExc VerifySignature verifySignature = null; try { verifySignature = appFactory.verifySignature(Algorithm.HS256, key); - } catch (InvalidJsonWebKeyException e) { - throw e; - } catch (InvalidAlgorithmException e) { + } catch (SignatureException e) { throw e; } diff --git a/src/test/java/examples/UnsecuredJsonWebTokenEncoder.java b/src/test/java/examples/UnsecuredJsonWebTokenEncoder.java deleted file mode 100644 index 6f8dfaa..0000000 --- a/src/test/java/examples/UnsecuredJsonWebTokenEncoder.java +++ /dev/null @@ -1,27 +0,0 @@ -package examples; - -import helper.entity.Claim; -import org.rootservices.jwt.UnSecureJwtEncoder; -import org.rootservices.jwt.factory.UnSecureJwtFactory; -import org.rootservices.jwt.config.AppFactory; -import org.rootservices.jwt.entity.jwt.JsonWebToken; -import org.rootservices.jwt.serializer.JWTSerializer; -import org.rootservices.jwt.serializer.exception.JwtToJsonException; - -/** - * Created by tommackenzie on 12/12/15. - */ -public class UnsecuredJsonWebTokenEncoder { - - public String toEncodedJwt() { - AppFactory appFactory = new AppFactory(); - UnSecureJwtEncoder unSecureJwtEncoder = appFactory.unSecureJwtEncoder(); - - Claim claim = new Claim(); - claim.setUriIsRoot(true); - - String encodedJwt = unSecureJwtEncoder.encode(claim); - - return encodedJwt; - } -} diff --git a/src/test/java/examples/UnsecuredJsonWebTokenSerializer.java b/src/test/java/examples/UnsecuredJsonWebTokenSerializer.java new file mode 100644 index 0000000..8448576 --- /dev/null +++ b/src/test/java/examples/UnsecuredJsonWebTokenSerializer.java @@ -0,0 +1,21 @@ +package examples; + +import helper.entity.Claim; +import org.rootservices.jwt.serialization.UnSecureJwtSerializer; +import org.rootservices.jwt.config.JwtAppFactory; + + +public class UnsecuredJsonWebTokenSerializer { + + public String toEncodedJwt() { + JwtAppFactory appFactory = new JwtAppFactory(); + UnSecureJwtSerializer unSecureJwtSerializer = appFactory.unSecureJwtSerializer(); + + Claim claim = new Claim(); + claim.setUriIsRoot(true); + + String encodedJwt = unSecureJwtSerializer.compactJwtToString(claim); + + return encodedJwt; + } +} diff --git a/src/test/java/helper/entity/Factory.java b/src/test/java/helper/entity/Factory.java index aaf692f..91f7e99 100644 --- a/src/test/java/helper/entity/Factory.java +++ b/src/test/java/helper/entity/Factory.java @@ -58,6 +58,16 @@ public static SymmetricKey makeSymmetricKey() { return key; } + public static SymmetricKey makeSymmetricKeyForJWE() { + SymmetricKey key = new SymmetricKey( + Optional.empty(), + "MMNj8rE5m7NIDhwKYDmHSnlU1wfKuVvW6G--GKPYkRA", + Use.ENCRYPTION + ); + + return key; + } + public static Claim makeClaim() { Claim claim = new Claim(); Optional issuer = Optional.of("joe"); @@ -81,4 +91,116 @@ public static JsonWebToken makeToken(Algorithm algorithm, Optional to return new JsonWebToken(header, claim); } + + public static byte[] aad() { + byte[] aad = "aad".getBytes(); + return aad; + } + + // taken from, https://tools.ietf.org/html/rfc7515#appendix-A.1 + public static RSAKeyPair makeRSAKeyPairForJWE() { + + + StringBuilder n = new StringBuilder(); + n.append("oahUIoWw0K0usKNuOR6H4wkf4oBUXHTxRvgb48E-BVvxkeDNjbC4he8rUW"); + n.append("cJoZmds2h7M70imEVhRU5djINXtqllXI4DFqcI1DgjT9LewND8MW2Krf3S"); + n.append("psk_ZkoFnilakGygTwpZ3uesH-PFABNIUYpOiN15dsQRkgr0vEhxN92i2a"); + n.append("sbOenSZeyaxziK72UwxrrKoExv6kc5twXTq4h-QChLOln0_mtUZwfsRaMS"); + n.append("tPs6mS6XrgxnxbWhojf663tuEQueGC-FCMfra36C9knDFGzKsNa7LZK2dj"); + n.append("YgyD3JR_MB_4NUJW_TqOQtwHYbxevoJArm-L5StowjzGy-_bq6Gw"); + + StringBuilder e = new StringBuilder(); + e.append("AQAB"); + + StringBuilder d = new StringBuilder(); + d.append("kLdtIj6GbDks_ApCSTYQtelcNttlKiOyPzMrXHeI-yk1F7-kpDxY4-WY5N"); + d.append("WV5KntaEeXS1j82E375xxhWMHXyvjYecPT9fpwR_M9gV8n9Hrh2anTpTD9"); + d.append("3Dt62ypW3yDsJzBnTnrYu1iwWRgBKrEYY46qAZIrA2xAwnm2X7uGR1hghk"); + d.append("qDp0Vqj3kbSCz1XyfCs6_LehBwtxHIyh8Ripy40p24moOAbgxVw3rxT_vl"); + d.append("t3UVe4WO3JkJOzlpUf-KTVI2Ptgm-dARxTEtE-id-4OJr0h-K-VFs3VSnd"); + d.append("VTIznSxfyrj8ILL6MG_Uv8YAu7VILSB3lOW085-4qE3DzgrTjgyQ"); + + StringBuilder p = new StringBuilder(); + p.append("1r52Xk46c-LsfB5P442p7atdPUrxQSy4mti_tZI3Mgf2EuFVbUoDBvaRQ-"); + p.append("SWxkbkmoEzL7JXroSBjSrK3YIQgYdMgyAEPTPjXv_hI2_1eTSPVZfzL0lf"); + p.append("fNn03IXqWF5MDFuoUYE0hzb2vhrlN_rKrbfDIwUbTrjjgieRbwC6Cl0"); + + StringBuilder q = new StringBuilder(); + q.append("wLb35x7hmQWZsWJmB_vle87ihgZ19S8lBEROLIsZG4ayZVe9Hi9gDVCOBm"); + q.append("UDdaDYVTSNx_8Fyw1YYa9XGrGnDew00J28cRUoeBB_jKI1oma0Orv1T9aX"); + q.append("IWxKwd4gvxFImOWr3QRL9KEBRzk2RatUBnmDZJTIAfwTs0g68UZHvtc"); + + StringBuilder dp = new StringBuilder(); + dp.append("ZK-YwE7diUh0qR1tR7w8WHtolDx3MZ_OTowiFvgfeQ3SiresXjm9gZ5KL"); + dp.append("hMXvo-uz-KUJWDxS5pFQ_M0evdo1dKiRTjVw_x4NyqyXPM5nULPkcpU827"); + dp.append("rnpZzAJKpdhWAgqrXGKAECQH0Xt4taznjnd_zVpAmZZq60WPMBMfKcuE"); + + StringBuilder dq = new StringBuilder(); + dq.append("Dq0gfgJ1DdFGXiLvQEZnuKEN0UUmsJBxkjydc3j4ZYdBiMRAy86x0vHCj"); + dq.append("ywcMlYYg4yoC4YZa9hNVcsjqA3FeiL19rk8g6Qn29Tt0cj8qqyFpz9vNDB"); + dq.append("UfCAiJVeESOjJDZPYHdHY8v1b-o-Z2X5tvLx-TCekf7oxyeKDUqKWjis"); + + StringBuilder qi = new StringBuilder(); + qi.append("VIMpMYbPf47dT1w_zDUXfPimsSegnMOA1zTaX7aGk_8urY6R8-ZW1FxU7"); + qi.append("AlWAyLWybqq6t16VFd7hQd0y6flUK4SlOydB61gwanOsXGOAOv82cHq0E3"); + qi.append("eL4HrtZkUuKvnPrMnsUUFlfUdybVzxyjz9JF_XyaY14ardLSjf4L_FNY"); + + return new RSAKeyPair( + Optional.empty(), + KeyType.RSA, + Use.ENCRYPTION, + toBigInt(n.toString()), + toBigInt(e.toString()), + toBigInt(d.toString()), + toBigInt(p.toString()), + toBigInt(q.toString()), + toBigInt(dp.toString()), + toBigInt(dq.toString()), + toBigInt(qi.toString()) + ); + } + + public static RSAPublicKey makeRSAPublicKeyForJWE() { + StringBuilder n = new StringBuilder(); + n.append("oahUIoWw0K0usKNuOR6H4wkf4oBUXHTxRvgb48E-BVvxkeDNjbC4he8rUW"); + n.append("cJoZmds2h7M70imEVhRU5djINXtqllXI4DFqcI1DgjT9LewND8MW2Krf3S"); + n.append("psk_ZkoFnilakGygTwpZ3uesH-PFABNIUYpOiN15dsQRkgr0vEhxN92i2a"); + n.append("sbOenSZeyaxziK72UwxrrKoExv6kc5twXTq4h-QChLOln0_mtUZwfsRaMS"); + n.append("tPs6mS6XrgxnxbWhojf663tuEQueGC-FCMfra36C9knDFGzKsNa7LZK2dj"); + n.append("YgyD3JR_MB_4NUJW_TqOQtwHYbxevoJArm-L5StowjzGy-_bq6Gw"); + + StringBuilder e = new StringBuilder(); + e.append("AQAB"); + + return new RSAPublicKey( + Optional.empty(), + KeyType.RSA, + Use.ENCRYPTION, + toBigInt(n.toString()), + toBigInt(e.toString()) + ); + + } + + // taken from, https://tools.ietf.org/html/rfc7516#section-3.3 + public static String compactJWE() { + StringBuilder encoded = new StringBuilder(); + encoded.append("eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ."); + encoded.append("OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGe"); + encoded.append("ipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDb"); + encoded.append("Sv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaV"); + encoded.append("mqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je8"); + encoded.append("1860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi"); + encoded.append("6UklfCpIMfIjf7iGdXKHzg."); + encoded.append("48V1_ALb6US04U3b."); + encoded.append("5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6ji"); + encoded.append("SdiwkIr3ajwQzaBtQD_A."); + encoded.append("XFBoMYUZodetZdvTiFvSkQ"); + + return encoded.toString(); + } + + public static String symmetricCompactJWE() { + return "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..0gDRrNTkCcMW_nnA1Q1yKUi0kJEAFxblm2-oUG0QhxEVtbzhWAlUnS5azsiC24Zk7Vv6DYOGCBkt2WSt_Yp2BYWrSHyxWVhNnQ0qtvm2TTh2MHjonN2Kb1NH_ooRLs6Z.NgpZSFNCr7s3SuA4mgoU1jY3bUi5KCp1pZwJ4VZT9yM8qduQaOAZj7qGRbxh.vSdENsFN2CpC1AunaZFJ-w"; + } } diff --git a/src/test/java/org/rootservices/jwt/SecureJwtEncoderTest.java b/src/test/java/org/rootservices/jwt/SecureJwtEncoderTest.java deleted file mode 100644 index 6264b66..0000000 --- a/src/test/java/org/rootservices/jwt/SecureJwtEncoderTest.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.rootservices.jwt; - -import helper.entity.Claim; -import helper.entity.Factory; -import org.junit.Before; -import org.junit.Test; -import org.rootservices.jwt.config.AppFactory; -import org.rootservices.jwt.entity.jwk.RSAKeyPair; -import org.rootservices.jwt.entity.jwk.SymmetricKey; -import org.rootservices.jwt.entity.jwt.header.Algorithm; -import org.rootservices.jwt.factory.SecureJwtFactory; - -import java.util.Optional; - -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.*; - -/** - * Created by tommackenzie on 9/3/16. - */ -public class SecureJwtEncoderTest { - private AppFactory appFactory; - - @Before - public void setUp() { - appFactory = new AppFactory(); - } - - @Test - public void encodeWithSymmetricKeyShouldEncode() throws Exception { - SymmetricKey key = Factory.makeSymmetricKey(); - key.setKeyId(Optional.of("test-key-id")); - - Claim claim = Factory.makeClaim(); - - SecureJwtEncoder subject = appFactory.secureJwtEncoder(Algorithm.HS256, key); - String jwt = subject.encode(claim); - - assertThat(jwt, is("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6InRlc3Qta2V5LWlkIn0.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.YiFm03WWrDAbFn7omROmU2GHACkaGI30xdbWFzyoCNQ")); - - } - - @Test - public void encodeWithAsymmetricKeyShouldEncode() throws Exception { - RSAKeyPair key = Factory.makeRSAKeyPair(); - key.setKeyId(Optional.of("test-key-id")); - - Claim claim = Factory.makeClaim(); - - SecureJwtEncoder subject = appFactory.secureJwtEncoder(Algorithm.RS256, key); - String jwt = subject.encode(claim); - - assertThat(jwt, is("eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6InRlc3Qta2V5LWlkIn0.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.JmMm15IjKsNB18oMqIIaIPHQ8TuqEXNdbmGyEya5Yuoo2Kj132PhiCt2gbPL2i75IH1Zmjvdc7Fm2eb2Db6P6NXezZEHgZG3WVTWJwl11lQnDnj6hTrTbHnL0XUgcFw0vIwthQF6NNjAy2lTMSG0KTH5y_3D-5pt6FM2cyfvK5RwhCom9v2MDWA7fTqR1u5L-_dfcgRlN5rjQ-QYBsk3oaNTMU9MtXtEuG7erun_-VXQJjXGwDRO_kPmzN-wILyoaOr670xpaHVmFLrTakjvfhCkLrB1YwdQV-B6ZFLqTpQpGr7ydEWMyuoiV0Xg71-mJhNHeml_jFMUwm-Lu-d2Og")); - } -} \ No newline at end of file diff --git a/src/test/java/org/rootservices/jwt/UnSecureJwtEncoderTest.java b/src/test/java/org/rootservices/jwt/UnSecureJwtEncoderTest.java deleted file mode 100644 index 029a15a..0000000 --- a/src/test/java/org/rootservices/jwt/UnSecureJwtEncoderTest.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.rootservices.jwt; - -import helper.entity.Factory; -import org.junit.Before; -import org.junit.Test; -import org.rootservices.jwt.config.AppFactory; -import org.rootservices.jwt.entity.jwt.Claims; - -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.*; - -/** - * Created by tommackenzie on 9/3/16. - */ -public class UnSecureJwtEncoderTest { - private AppFactory appFactory; - - @Before - public void setUp() { - appFactory = new AppFactory(); - } - - @Test - public void encodeShouldEncode() { - UnSecureJwtEncoder subject = appFactory.unSecureJwtEncoder(); - - Claims claims = Factory.makeClaim(); - - String jwt = subject.encode(claims); - - assertThat(jwt, is("eyJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.")); - } - -} \ No newline at end of file diff --git a/src/test/java/org/rootservices/jwt/factory/SecureJwtFactoryTest.java b/src/test/java/org/rootservices/jwt/factory/SecureJwtFactoryTest.java index 1adccdc..cd5f976 100644 --- a/src/test/java/org/rootservices/jwt/factory/SecureJwtFactoryTest.java +++ b/src/test/java/org/rootservices/jwt/factory/SecureJwtFactoryTest.java @@ -4,15 +4,15 @@ import helper.entity.Factory; import org.junit.Before; import org.junit.Test; -import org.rootservices.jwt.config.AppFactory; +import org.rootservices.jwt.config.JwtAppFactory; import org.rootservices.jwt.entity.jwk.RSAKeyPair; import org.rootservices.jwt.entity.jwk.SymmetricKey; import org.rootservices.jwt.entity.jwt.JsonWebToken; import org.rootservices.jwt.entity.jwt.header.Algorithm; import org.rootservices.jwt.entity.jwt.header.TokenType; -import org.rootservices.jwt.serializer.exception.JwtToJsonException; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidAlgorithmException; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidJsonWebKeyException; +import org.rootservices.jwt.serialization.exception.JwtToJsonException; +import org.rootservices.jwt.jws.signer.factory.exception.InvalidAlgorithmException; +import org.rootservices.jwt.jws.signer.factory.exception.InvalidJsonWebKeyException; import java.util.Optional; @@ -23,16 +23,14 @@ import static org.junit.Assert.assertThat; -/** - * Created by tommackenzie on 9/15/15. - */ + public class SecureJwtFactoryTest { - private AppFactory appFactory; + private JwtAppFactory appFactory; @Before public void setUp(){ - appFactory = new AppFactory(); + appFactory = new JwtAppFactory(); } @@ -86,7 +84,7 @@ public void buildWithSymmetricKeyShouldHaveValidHeaderClaimsSignature() throws E // inspect signature. assertThat(actual.getSignature().isPresent(), is(true)); - assertThat(actual.getSignature().get(), is("lliDzOlRAdGUCfCHCPx_uisb6ZfZ1LRQa0OJLeYTTpY")); + assertThat(actual.getSignature().get(), is("lliDzOlRAdGUCfCHCPx_uisb6ZfZ1LRQa0OJLeYTTpY".getBytes())); // claims ivars that were not assigned. assertThat(actualClaim.getSubject().isPresent(), is(false)); @@ -137,7 +135,7 @@ public void buildWithRSAKeyPairShouldHaveValidHeaderClaimsSignature() throws Exc // inspect signature. assertThat(actual.getSignature().isPresent(), is(true)); - assertThat(actual.getSignature().get(), is("IDcgYnWIJ0my4FurSqfiAAbYBz2BfImT-uSqKKnk-JfncL_Nreo8Phol1KNn9fK0ZmVfcvHL-pUvVUBzI5NrJNCFMiyZWxS7msB2VKl6-jAXr9NqtVjIDyUSr_gpk51xSzHiBPVAnQn8m1Dg3dR0YkP9b5uJ70qpZ37PWOCKYAIfAhinDA77RIP9q4ImwpnJuY3IDuilDKOq9bsb6zWB8USz0PAYReqWierdS4TYAbUFrhuGZ9mPgSLRSQVtibyNTSTQYtfghYkmV9gWyCJUVwMGCM5l1xlylHYiioasBJA1Wr_NAf_sr4G8OVrW1eO01MKhijpaE8pR6DvPYNrTMQ")); + assertThat(actual.getSignature().get(), is("IDcgYnWIJ0my4FurSqfiAAbYBz2BfImT-uSqKKnk-JfncL_Nreo8Phol1KNn9fK0ZmVfcvHL-pUvVUBzI5NrJNCFMiyZWxS7msB2VKl6-jAXr9NqtVjIDyUSr_gpk51xSzHiBPVAnQn8m1Dg3dR0YkP9b5uJ70qpZ37PWOCKYAIfAhinDA77RIP9q4ImwpnJuY3IDuilDKOq9bsb6zWB8USz0PAYReqWierdS4TYAbUFrhuGZ9mPgSLRSQVtibyNTSTQYtfghYkmV9gWyCJUVwMGCM5l1xlylHYiioasBJA1Wr_NAf_sr4G8OVrW1eO01MKhijpaE8pR6DvPYNrTMQ".getBytes())); // claims ivars that were not assigned. assertThat(actualClaim.getSubject().isPresent(), is(false)); @@ -182,14 +180,14 @@ public void buildTwiceWithRSAKeyPairShouldSignsCorrectly() throws JwtToJsonExcep assertThat(actual, is(notNullValue())); assertThat(actual.getSignature().isPresent(), is(true)); - assertThat(actual.getSignature().get(), is("IDcgYnWIJ0my4FurSqfiAAbYBz2BfImT-uSqKKnk-JfncL_Nreo8Phol1KNn9fK0ZmVfcvHL-pUvVUBzI5NrJNCFMiyZWxS7msB2VKl6-jAXr9NqtVjIDyUSr_gpk51xSzHiBPVAnQn8m1Dg3dR0YkP9b5uJ70qpZ37PWOCKYAIfAhinDA77RIP9q4ImwpnJuY3IDuilDKOq9bsb6zWB8USz0PAYReqWierdS4TYAbUFrhuGZ9mPgSLRSQVtibyNTSTQYtfghYkmV9gWyCJUVwMGCM5l1xlylHYiioasBJA1Wr_NAf_sr4G8OVrW1eO01MKhijpaE8pR6DvPYNrTMQ")); + assertThat(actual.getSignature().get(), is("IDcgYnWIJ0my4FurSqfiAAbYBz2BfImT-uSqKKnk-JfncL_Nreo8Phol1KNn9fK0ZmVfcvHL-pUvVUBzI5NrJNCFMiyZWxS7msB2VKl6-jAXr9NqtVjIDyUSr_gpk51xSzHiBPVAnQn8m1Dg3dR0YkP9b5uJ70qpZ37PWOCKYAIfAhinDA77RIP9q4ImwpnJuY3IDuilDKOq9bsb6zWB8USz0PAYReqWierdS4TYAbUFrhuGZ9mPgSLRSQVtibyNTSTQYtfghYkmV9gWyCJUVwMGCM5l1xlylHYiioasBJA1Wr_NAf_sr4G8OVrW1eO01MKhijpaE8pR6DvPYNrTMQ".getBytes())); // second JsonWebToken actual = subject.makeJwt(claim); assertThat(actual, is(notNullValue())); assertThat(actual.getSignature().isPresent(), is(true)); - assertThat(actual.getSignature().get(), is("IDcgYnWIJ0my4FurSqfiAAbYBz2BfImT-uSqKKnk-JfncL_Nreo8Phol1KNn9fK0ZmVfcvHL-pUvVUBzI5NrJNCFMiyZWxS7msB2VKl6-jAXr9NqtVjIDyUSr_gpk51xSzHiBPVAnQn8m1Dg3dR0YkP9b5uJ70qpZ37PWOCKYAIfAhinDA77RIP9q4ImwpnJuY3IDuilDKOq9bsb6zWB8USz0PAYReqWierdS4TYAbUFrhuGZ9mPgSLRSQVtibyNTSTQYtfghYkmV9gWyCJUVwMGCM5l1xlylHYiioasBJA1Wr_NAf_sr4G8OVrW1eO01MKhijpaE8pR6DvPYNrTMQ")); + assertThat(actual.getSignature().get(), is("IDcgYnWIJ0my4FurSqfiAAbYBz2BfImT-uSqKKnk-JfncL_Nreo8Phol1KNn9fK0ZmVfcvHL-pUvVUBzI5NrJNCFMiyZWxS7msB2VKl6-jAXr9NqtVjIDyUSr_gpk51xSzHiBPVAnQn8m1Dg3dR0YkP9b5uJ70qpZ37PWOCKYAIfAhinDA77RIP9q4ImwpnJuY3IDuilDKOq9bsb6zWB8USz0PAYReqWierdS4TYAbUFrhuGZ9mPgSLRSQVtibyNTSTQYtfghYkmV9gWyCJUVwMGCM5l1xlylHYiioasBJA1Wr_NAf_sr4G8OVrW1eO01MKhijpaE8pR6DvPYNrTMQ".getBytes())); } @@ -208,14 +206,14 @@ public void buildTwiceWithSymmetricKeyShouldSignsCorrectly() throws JwtToJsonExc assertThat(actual, is(notNullValue())); assertThat(actual.getSignature().isPresent(), is(true)); - assertThat(actual.getSignature().get(), is("lliDzOlRAdGUCfCHCPx_uisb6ZfZ1LRQa0OJLeYTTpY")); + assertThat(actual.getSignature().get(), is("lliDzOlRAdGUCfCHCPx_uisb6ZfZ1LRQa0OJLeYTTpY".getBytes())); // second JsonWebToken actual = subject.makeJwt(claim); assertThat(actual, is(notNullValue())); assertThat(actual.getSignature().isPresent(), is(true)); - assertThat(actual.getSignature().get(), is("lliDzOlRAdGUCfCHCPx_uisb6ZfZ1LRQa0OJLeYTTpY")); + assertThat(actual.getSignature().get(), is("lliDzOlRAdGUCfCHCPx_uisb6ZfZ1LRQa0OJLeYTTpY".getBytes())); } } \ No newline at end of file diff --git a/src/test/java/org/rootservices/jwt/factory/UnSecureJwtFactoryTest.java b/src/test/java/org/rootservices/jwt/factory/UnSecureJwtFactoryTest.java index e31e2eb..12d8383 100644 --- a/src/test/java/org/rootservices/jwt/factory/UnSecureJwtFactoryTest.java +++ b/src/test/java/org/rootservices/jwt/factory/UnSecureJwtFactoryTest.java @@ -2,7 +2,7 @@ import org.junit.Before; import org.junit.Test; -import org.rootservices.jwt.config.AppFactory; +import org.rootservices.jwt.config.JwtAppFactory; import org.rootservices.jwt.entity.jwt.JsonWebToken; import helper.entity.Claim; @@ -24,7 +24,7 @@ public class UnSecureJwtFactoryTest { @Before public void setUp(){ - AppFactory appFactory = new AppFactory(); + JwtAppFactory appFactory = new JwtAppFactory(); subject = appFactory.unsecureJwtFactory(); } diff --git a/src/test/java/org/rootservices/jwt/jwe/factory/CipherRSAFactoryTest.java b/src/test/java/org/rootservices/jwt/jwe/factory/CipherRSAFactoryTest.java new file mode 100644 index 0000000..5a02ed2 --- /dev/null +++ b/src/test/java/org/rootservices/jwt/jwe/factory/CipherRSAFactoryTest.java @@ -0,0 +1,59 @@ +package org.rootservices.jwt.jwe.factory; + +import helper.entity.Factory; +import org.junit.Before; +import org.junit.Test; +import org.rootservices.jwt.config.JwtAppFactory; +import org.rootservices.jwt.jwe.Transformation; +import org.rootservices.jwt.entity.jwk.RSAKeyPair; +import org.rootservices.jwt.entity.jwk.RSAPublicKey; +import org.rootservices.jwt.jwk.PrivateKeyFactory; +import org.rootservices.jwt.jwk.PublicKeyFactory; + +import javax.crypto.Cipher; + +import java.security.interfaces.RSAPrivateCrtKey; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.*; + +public class CipherRSAFactoryTest { + private PublicKeyFactory publicKeyFactory; + private PrivateKeyFactory privateKeyFactory; + private CipherRSAFactory subject; + + @Before + public void setUp() { + JwtAppFactory jwtAppFactory = new JwtAppFactory(); + publicKeyFactory = jwtAppFactory.publicKeyFactory(); + privateKeyFactory = jwtAppFactory.privateKeyFactory(); + subject = new CipherRSAFactory(); + } + + @Test + public void forEncryptWhenPublicKey() throws Exception { + + RSAPublicKey rsaPublicKey = Factory.makeRSAPublicKey(); + java.security.interfaces.RSAPublicKey jdkPublicKey = publicKeyFactory.makePublicKey(rsaPublicKey); + + Cipher actual = subject.forEncrypt(Transformation.RSA_OAEP, jdkPublicKey); + + assertThat(actual, is(notNullValue())); + assertThat(actual.getAlgorithm(), is(Transformation.RSA_OAEP.getValue())); + assertThat(actual.getIV(), is(nullValue())); + } + + @Test + public void forDecryptWhenPrivateKey() throws Exception { + RSAKeyPair jwk = Factory.makeRSAKeyPair(); + RSAPrivateCrtKey jdkPrivateKey = privateKeyFactory.makePrivateKey(jwk); + + Cipher actual = subject.forDecrypt(Transformation.RSA_OAEP, jdkPrivateKey); + + assertThat(actual, is(notNullValue())); + assertThat(actual.getAlgorithm(), is(Transformation.RSA_OAEP.getValue())); + assertThat(actual.getIV(), is(nullValue())); + } +} \ No newline at end of file diff --git a/src/test/java/org/rootservices/jwt/jwe/factory/CipherSymmetricFactoryTest.java b/src/test/java/org/rootservices/jwt/jwe/factory/CipherSymmetricFactoryTest.java new file mode 100644 index 0000000..940ef81 --- /dev/null +++ b/src/test/java/org/rootservices/jwt/jwe/factory/CipherSymmetricFactoryTest.java @@ -0,0 +1,54 @@ +package org.rootservices.jwt.jwe.factory; + + +import helper.entity.Factory; +import org.junit.Before; +import org.junit.Test; +import org.rootservices.jwt.jwe.Transformation; +import org.rootservices.jwt.jwk.KeyAlgorithm; +import org.rootservices.jwt.jwk.SecretKeyFactory; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.*; + +public class CipherSymmetricFactoryTest { + + private CipherSymmetricFactory subject; + + @Before + public void setUp() { + subject = new CipherSymmetricFactory(); + } + + @Test + public void forEncryptWhenSecretKey() throws Exception { + SecretKeyFactory secretKeyFactory = new SecretKeyFactory(); + SecretKey secretKey = secretKeyFactory.makeKey(KeyAlgorithm.AES); + byte[] aad = Factory.aad(); + + Cipher actual = subject.forEncrypt(Transformation.AES_GCM_NO_PADDING, secretKey, aad); + + assertThat(actual, is(notNullValue())); + assertThat(actual.getAlgorithm(), is(Transformation.AES_GCM_NO_PADDING.getValue())); + assertThat(actual.getIV(), is(notNullValue())); + } + + @Test + public void forDecryptWhenSecretKey() throws Exception { + SecretKeyFactory secretKeyFactory = new SecretKeyFactory(); + SecretKey secretKey = secretKeyFactory.makeKey(KeyAlgorithm.AES); + byte[] aad = Factory.aad(); + + byte[] initVector = subject.makeInitVector(); + Cipher actual = subject.forDecrypt(Transformation.AES_GCM_NO_PADDING, secretKey, initVector, aad); + + assertThat(actual, is(notNullValue())); + assertThat(actual.getAlgorithm(), is(Transformation.AES_GCM_NO_PADDING.getValue())); + assertThat(actual.getIV(), is(notNullValue())); + assertThat(actual.getIV(), is(initVector)); + } +} \ No newline at end of file diff --git a/src/test/java/org/rootservices/jwt/jwe/factory/SecretKeyFactoryTest.java b/src/test/java/org/rootservices/jwt/jwe/factory/SecretKeyFactoryTest.java new file mode 100644 index 0000000..98fd21f --- /dev/null +++ b/src/test/java/org/rootservices/jwt/jwe/factory/SecretKeyFactoryTest.java @@ -0,0 +1,29 @@ +package org.rootservices.jwt.jwe.factory; + +import org.junit.Before; +import org.junit.Test; +import org.rootservices.jwt.jwk.KeyAlgorithm; +import org.rootservices.jwt.jwk.SecretKeyFactory; + +import javax.crypto.SecretKey; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.*; + +public class SecretKeyFactoryTest { + private SecretKeyFactory subject; + + @Before + public void setUp() { + subject = new SecretKeyFactory(); + } + @Test + public void makeKeyForAESAnd256ShouldBeOk() throws Exception { + SecretKey actual = subject.makeKey(KeyAlgorithm.AES); + + assertThat(actual, is(notNullValue())); + assertThat(actual.getAlgorithm(), is(KeyAlgorithm.AES.getValue())); + assertThat(actual.getEncoded(), is(notNullValue())); + } +} \ No newline at end of file diff --git a/src/test/java/org/rootservices/jwt/jwe/serialization/direct/JweDirectDesializerTest.java b/src/test/java/org/rootservices/jwt/jwe/serialization/direct/JweDirectDesializerTest.java new file mode 100644 index 0000000..289a26a --- /dev/null +++ b/src/test/java/org/rootservices/jwt/jwe/serialization/direct/JweDirectDesializerTest.java @@ -0,0 +1,48 @@ +package org.rootservices.jwt.jwe.serialization.direct; + +import helper.entity.Factory; +import org.hamcrest.CoreMatchers; +import org.junit.Test; +import org.rootservices.jwt.config.JwtAppFactory; +import org.rootservices.jwt.entity.jwe.EncryptionAlgorithm; +import org.rootservices.jwt.entity.jwk.SymmetricKey; +import org.rootservices.jwt.entity.jwt.header.Algorithm; +import org.rootservices.jwt.entity.jwt.header.AlgorithmFor; +import org.rootservices.jwt.jwe.entity.JWE; +import org.rootservices.jwt.jwe.serialization.JweDeserializer; + +import java.nio.charset.StandardCharsets; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.*; + +public class JweDirectDesializerTest { + private static JwtAppFactory jwtAppFactory = new JwtAppFactory(); + + @Test + public void stringToJWE() throws Exception { + JweDeserializer subject = jwtAppFactory.jweDirectDesializer(); + + SymmetricKey key = Factory.makeSymmetricKeyForJWE(); + String compactJwe = Factory.symmetricCompactJWE(); + + JWE actual = subject.stringToJWE(compactJwe, key); + + assertThat(actual, is(notNullValue())); + + assertThat(actual.getHeader().getKeyId().isPresent(), CoreMatchers.is(false)); + assertThat(actual.getHeader().getType().isPresent(), CoreMatchers.is(false)); + assertThat(actual.getHeader().getAlgorithm(), CoreMatchers.is(Algorithm.DIRECT)); + assertThat(actual.getHeader().getAlgorithm().getAlgorithmFor(), CoreMatchers.is(AlgorithmFor.JWE)); + assertThat(actual.getHeader().getEncryptionAlgorithm().isPresent(), CoreMatchers.is(true)); + assertThat(actual.getHeader().getEncryptionAlgorithm().get(), CoreMatchers.is(EncryptionAlgorithm.AES_GCM_256)); + + assertThat(actual.getCek(), CoreMatchers.is(CoreMatchers.notNullValue())); + assertThat(actual.getIv(), CoreMatchers.is(CoreMatchers.notNullValue())); + assertThat(actual.getAuthTag(), CoreMatchers.is(CoreMatchers.notNullValue())); + + String payload = new String(actual.getPayload(), StandardCharsets.UTF_8); + assertThat(payload, CoreMatchers.is("Help me, Obi-Wan Kenobi. You're my only hope.")); + } +} \ No newline at end of file diff --git a/src/test/java/org/rootservices/jwt/jwe/serialization/direct/JweDirectSerdesTest.java b/src/test/java/org/rootservices/jwt/jwe/serialization/direct/JweDirectSerdesTest.java new file mode 100644 index 0000000..9c5034e --- /dev/null +++ b/src/test/java/org/rootservices/jwt/jwe/serialization/direct/JweDirectSerdesTest.java @@ -0,0 +1,76 @@ +package org.rootservices.jwt.jwe.serialization.direct; + +import helper.entity.Factory; +import org.hamcrest.CoreMatchers; +import org.junit.Test; +import org.rootservices.jwt.config.JwtAppFactory; +import org.rootservices.jwt.entity.jwe.EncryptionAlgorithm; +import org.rootservices.jwt.entity.jwk.SymmetricKey; +import org.rootservices.jwt.entity.jwt.header.Algorithm; +import org.rootservices.jwt.entity.jwt.header.Header; +import org.rootservices.jwt.jwe.entity.JWE; +import org.rootservices.jwt.jwe.serialization.JweDeserializer; +import org.rootservices.jwt.jwe.serialization.JweSerializer; +import org.rootservices.jwt.jwe.serialization.rsa.JweRsaDeserializer; + +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.Optional; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.*; +import static org.mockito.Matchers.notNull; + +public class JweDirectSerdesTest { + private static JwtAppFactory jwtAppFactory = new JwtAppFactory(); + + @Test + public void JWEToCompact() throws Exception { + JweSerializer subject = jwtAppFactory.jweDirectSerializer(); + + SymmetricKey key = Factory.makeSymmetricKeyForJWE(); + + Base64.Decoder decoder = jwtAppFactory.urlDecoder(); + + Header header = new Header(); + header.setEncryptionAlgorithm(Optional.of(EncryptionAlgorithm.AES_GCM_256)); + header.setAlgorithm(Algorithm.DIRECT); + + JWE jwe = new JWE(); + jwe.setHeader(header); + jwe.setCek(decoder.decode(key.getKey())); + jwe.setPayload("Help me, Obi-Wan Kenobi. You're my only hope.".getBytes()); + + ByteArrayOutputStream actual = subject.JWEToCompact(jwe); + assertThat(actual, is(notNullValue())); + + String compactJWE = actual.toString(); + + String[] jweParts = compactJWE.split("\\."); + String protectedHeader = new String(decoder.decode(jweParts[0]), StandardCharsets.UTF_8); + String encryptedKey = new String(decoder.decode(jweParts[1]), StandardCharsets.UTF_8); + String initVector = new String(decoder.decode(jweParts[2]), StandardCharsets.UTF_8); + String cipherText = new String(decoder.decode(jweParts[3]), StandardCharsets.UTF_8); + String authenticationTag = new String(decoder.decode(jweParts[4]), StandardCharsets.UTF_8); + + assertThat(protectedHeader, is(notNullValue())); + + assertThat(encryptedKey, is(notNullValue())); + assertThat(encryptedKey, is("")); + + assertThat(initVector, is(notNullValue())); + assertThat(cipherText, is(notNullValue())); + assertThat(authenticationTag, is(notNullValue())); + + // should be able to deserialize it. + JweDeserializer jweDeserializer = jwtAppFactory.jweDirectDesializer(); + + JWE leia = jweDeserializer.stringToJWE(compactJWE, key); + + assertThat(leia, CoreMatchers.is(CoreMatchers.notNullValue())); + String payload = new String(leia.getPayload()); + assertThat(payload, CoreMatchers.is("Help me, Obi-Wan Kenobi. You're my only hope.")); + } +} \ No newline at end of file diff --git a/src/test/java/org/rootservices/jwt/jwe/serialization/rsa/JweRsaDeserializerTest.java b/src/test/java/org/rootservices/jwt/jwe/serialization/rsa/JweRsaDeserializerTest.java new file mode 100644 index 0000000..fb4bc2e --- /dev/null +++ b/src/test/java/org/rootservices/jwt/jwe/serialization/rsa/JweRsaDeserializerTest.java @@ -0,0 +1,47 @@ +package org.rootservices.jwt.jwe.serialization.rsa; + +import helper.entity.Factory; +import org.junit.Test; +import org.rootservices.jwt.config.JwtAppFactory; +import org.rootservices.jwt.entity.jwe.EncryptionAlgorithm; +import org.rootservices.jwt.entity.jwk.RSAKeyPair; +import org.rootservices.jwt.entity.jwt.header.Algorithm; +import org.rootservices.jwt.entity.jwt.header.AlgorithmFor; +import org.rootservices.jwt.jwe.entity.JWE; + + +import java.nio.charset.StandardCharsets; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.*; + +public class JweRsaDeserializerTest { + + @Test + public void stringToJWE() throws Exception { + JwtAppFactory jwtAppFactory = new JwtAppFactory(); + RSAKeyPair jwk = Factory.makeRSAKeyPairForJWE(); + JweRsaDeserializer subject = jwtAppFactory.jweRsaDeserializer(); + + String compactJWE = Factory.compactJWE(); + + JWE actual = subject.stringToJWE(compactJWE, jwk); + + assertThat(actual, is(notNullValue())); + + assertThat(actual.getHeader().getKeyId().isPresent(), is(false)); + assertThat(actual.getHeader().getType().isPresent(), is(false)); + assertThat(actual.getHeader().getAlgorithm(), is(Algorithm.RSAES_OAEP)); + assertThat(actual.getHeader().getAlgorithm().getAlgorithmFor(), is(AlgorithmFor.JWE)); + assertThat(actual.getHeader().getEncryptionAlgorithm().isPresent(), is(true)); + assertThat(actual.getHeader().getEncryptionAlgorithm().get(), is(EncryptionAlgorithm.AES_GCM_256)); + + assertThat(actual.getCek(), is(notNullValue())); + assertThat(actual.getIv(), is(notNullValue())); + assertThat(actual.getAuthTag(), is(notNullValue())); + + String payload = new String(actual.getPayload(), StandardCharsets.UTF_8); + assertThat(payload, is("The true sign of intelligence is not knowledge but imagination.")); + } +} \ No newline at end of file diff --git a/src/test/java/org/rootservices/jwt/jwe/serialization/rsa/JweRsaSerdesTest.java b/src/test/java/org/rootservices/jwt/jwe/serialization/rsa/JweRsaSerdesTest.java new file mode 100644 index 0000000..4b02144 --- /dev/null +++ b/src/test/java/org/rootservices/jwt/jwe/serialization/rsa/JweRsaSerdesTest.java @@ -0,0 +1,114 @@ +package org.rootservices.jwt.jwe.serialization.rsa; + +import helper.entity.Factory; +import org.junit.Test; +import org.rootservices.jwt.config.JwtAppFactory; +import org.rootservices.jwt.entity.jwe.EncryptionAlgorithm; +import org.rootservices.jwt.entity.jwk.RSAKeyPair; +import org.rootservices.jwt.entity.jwk.RSAPublicKey; +import org.rootservices.jwt.entity.jwk.SymmetricKey; +import org.rootservices.jwt.entity.jwt.header.Algorithm; +import org.rootservices.jwt.entity.jwt.header.Header; +import org.rootservices.jwt.jwe.entity.JWE; + + +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.Optional; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.*; + +public class JweRsaSerdesTest { + + @Test + public void extractCipherText() throws Exception { + JwtAppFactory jwtAppFactory = new JwtAppFactory(); + Base64.Decoder decoder = jwtAppFactory.urlDecoder(); + String compactJWE = Factory.compactJWE(); + + String[] jweParts = compactJWE.split(JweRsaDeserializer.JWT_SPLITTER); + byte[] protectedHeader = decoder.decode(jweParts[0]); + byte[] encryptedKey = decoder.decode(jweParts[1]); + byte[] initVector = decoder.decode(jweParts[2]); + byte[] cipherText = decoder.decode(jweParts[3]); + byte[] authenticationTag = decoder.decode(jweParts[4]); + + RSAKeyPair jwk = Factory.makeRSAKeyPairForJWE(); + JweRsaDeserializer JweRsaDeserializer = jwtAppFactory.jweRsaDeserializer(); + + RSAPublicKey publicKey = Factory.makeRSAPublicKeyForJWE(); + JweRsaSerializer subject = jwtAppFactory.jweRsaSerializer(publicKey); + + byte[] cipherTextWithAuthTag = JweRsaDeserializer.cipherTextWithAuthTag(cipherText, authenticationTag); + + assertThat(cipherTextWithAuthTag.length, is(cipherText.length + authenticationTag.length)); + + byte[] actual = subject.extractCipherText(cipherTextWithAuthTag); + assertThat(actual.length, is(cipherText.length)); + assertThat(actual, is(cipherText)); + } + + @Test + public void extractAuthTag() throws Exception { + JwtAppFactory jwtAppFactory = new JwtAppFactory(); + Base64.Decoder decoder = jwtAppFactory.urlDecoder(); + String compactJWE = Factory.compactJWE(); + + String[] jweParts = compactJWE.split(JweRsaDeserializer.JWT_SPLITTER); + byte[] protectedHeader = decoder.decode(jweParts[0]); + byte[] encryptedKey = decoder.decode(jweParts[1]); + byte[] initVector = decoder.decode(jweParts[2]); + byte[] cipherText = decoder.decode(jweParts[3]); + byte[] authenticationTag = decoder.decode(jweParts[4]); + + + RSAKeyPair jwk = Factory.makeRSAKeyPairForJWE(); + JweRsaDeserializer JweRsaDeserializer = jwtAppFactory.jweRsaDeserializer(); + + RSAPublicKey publicKey = Factory.makeRSAPublicKeyForJWE(); + JweRsaSerializer subject = jwtAppFactory.jweRsaSerializer(publicKey); + + byte[] cipherTextWithAuthTag = JweRsaDeserializer.cipherTextWithAuthTag(cipherText, authenticationTag); + + assertThat(cipherTextWithAuthTag.length, is(cipherText.length + authenticationTag.length)); + + byte[] actual = subject.extractAuthTag(cipherTextWithAuthTag); + assertThat(actual.length, is(authenticationTag.length)); + assertThat(actual, is(authenticationTag)); + } + + @Test + public void JWEToCompact() throws Exception { + JwtAppFactory jwtAppFactory = new JwtAppFactory(); + + RSAPublicKey publicKey = Factory.makeRSAPublicKeyForJWE(); + JweRsaSerializer subject = jwtAppFactory.jweRsaSerializer(publicKey); + + Header header = new Header(); + header.setEncryptionAlgorithm(Optional.of(EncryptionAlgorithm.AES_GCM_256)); + header.setAlgorithm(Algorithm.RSAES_OAEP); + + JWE jwe = new JWE(); + jwe.setHeader(header); + jwe.setPayload("Help me, Obi-Wan Kenobi. You're my only hope.".getBytes()); + + ByteArrayOutputStream actual = subject.JWEToCompact(jwe); + + // make sure it can be read. + RSAKeyPair jwk = Factory.makeRSAKeyPairForJWE(); + JweRsaDeserializer JweRsaDeserializer = jwtAppFactory.jweRsaDeserializer(); + + String compactJWE = actual.toString(); + + JWE leia = JweRsaDeserializer.stringToJWE(compactJWE, jwk); + + assertThat(leia, is(notNullValue())); + String payload = new String(leia.getPayload()); + assertThat(payload, is("Help me, Obi-Wan Kenobi. You're my only hope.")); + + } + +} \ No newline at end of file diff --git a/src/test/java/org/rootservices/jwt/jwk/PrivateKeyFactoryTest.java b/src/test/java/org/rootservices/jwt/jwk/PrivateKeyFactoryTest.java new file mode 100644 index 0000000..4de92d7 --- /dev/null +++ b/src/test/java/org/rootservices/jwt/jwk/PrivateKeyFactoryTest.java @@ -0,0 +1,67 @@ +package org.rootservices.jwt.jwk; + +import helper.entity.Factory; +import org.junit.Before; +import org.junit.Test; +import org.rootservices.jwt.config.JwtAppFactory; +import org.rootservices.jwt.entity.jwk.RSAKeyPair; +import org.rootservices.jwt.jws.signer.factory.rsa.exception.PrivateKeyException; + +import java.math.BigInteger; +import java.security.interfaces.RSAPrivateCrtKey; + +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.*; + +public class PrivateKeyFactoryTest { + private PrivateKeyFactory subject; + + @Before + public void setUp() { + JwtAppFactory jwtAppFactory = new JwtAppFactory(); + subject = jwtAppFactory.privateKeyFactory(); + } + + @Test + public void makePrivateKeyShouldMakeRSAPrivateCrtKey() throws Exception { + RSAKeyPair jwk = Factory.makeRSAKeyPair(); + RSAPrivateCrtKey privateKey = subject.makePrivateKey(jwk); + + // expected values + BigInteger modulus = new BigInteger("20446702916744654562596343388758805860065209639960173505037453331270270518732245089773723012043203236097095623402044690115755377345254696448759605707788965848889501746836211206270643833663949992536246985362693736387185145424787922241585721992924045675229348655595626434390043002821512765630397723028023792577935108185822753692574221566930937805031155820097146819964920270008811327036286786392793593121762425048860211859763441770446703722015857250621107855398693133264081150697423188751482418465308470313958250757758547155699749157985955379381294962058862159085915015369381046959790476428631998204940879604226680285601"); + BigInteger publicExponent = new BigInteger("65537"); + BigInteger privateExponent = new BigInteger("2358310989939619510179986262349936882924652023566213765118606431955566700506538911356936879137503597382515919515633242482643314423192704128296593672966061810149316320617894021822784026407461403384065351821972350784300967610143459484324068427674639688405917977442472804943075439192026107319532117557545079086537982987982522396626690057355718157403493216553255260857777965627529169195827622139772389760130571754834678679842181142252489617665030109445573978012707793010592737640499220015083392425914877847840457278246402760955883376999951199827706285383471150643561410605789710883438795588594095047409018233862167884701"); + BigInteger primeP = new BigInteger("157377055902447438395586165028960291914931973278777532798470200156035267537359239071829408411909323208574959800537247728959718236884809685233284537349207654661530801859889389455120932077199406250387226339056140578989122526711937239401762061949364440402067108084155200696015505170135950332209194782224750221639"); + BigInteger primeQ = new BigInteger("129921752567406358990993347540064445018230073402482260994179328573323861908379211274626956543471664997237185298964648133324343327052852264060322088122401124781249085873464824282666514908127141915943024862618996371026577302203267804867959037802770797169483022132210859867700312376409633383772189122488119155159"); + BigInteger primeExponentP = new BigInteger("4922760648183732070600601771661330216909692924935440167185924139339187000497222028735680413269055839870281941362914961691371628021024152077883230870590287807744299308982303864732867094286567630701646611762288298013758658158894538059014178662376933683632720014228880806671525788467258162275185762295508460173"); + BigInteger primeExponentQ = new BigInteger("95501022448116849078110281587424883261489167280943290677534750975651978631525094586933777934986404467352856624385049043666431411835209194330560695076194390729082708437497817187133629692908081460223069101908960299950170666285307890683263785145958472051553704139602453015343925544671829327400421727981791235189"); + BigInteger crtCoefficient = new BigInteger("23545019917990284444784037831882732213707743418529123971725460465297450415859883707284136179135646366158633580054594447195052813412945775933274620822213099556720089770059982091144435545976515508108465724188242241967967709555336331874325396876783846248039429242763646988988076187339075374375350105207330456437"); + + assertThat(privateKey, is(notNullValue())); + assertThat(privateKey.getAlgorithm(), is("RSA")); + assertThat(privateKey.getModulus(), is(modulus)); + assertThat(privateKey.getPublicExponent(), is(publicExponent)); + assertThat(privateKey.getPrivateExponent(), is(privateExponent)); + assertThat(privateKey.getPrimeP(), is(primeP)); + assertThat(privateKey.getPrimeQ(), is(primeQ)); + assertThat(privateKey.getPrimeExponentP(), is(primeExponentP)); + assertThat(privateKey.getPrimeExponentQ(), is(primeExponentQ)); + assertThat(privateKey.getCrtCoefficient(), is(crtCoefficient)); + } + + @Test + public void makePrivateKeyWhenKeyIsNot512ShouldThrowPrivateKeyException() throws Exception { + RSAKeyPair rsaKeyPair = Factory.makeRSAKeyPair(); + rsaKeyPair.setN(new BigInteger("1")); + + PrivateKeyException actual = null; + try { + subject.makePrivateKey(rsaKeyPair); + } catch (PrivateKeyException e) { + actual = e; + } + + assertThat(actual, is(notNullValue())); + } +} \ No newline at end of file diff --git a/src/test/java/org/rootservices/jwt/jwk/PublicKeyFactoryTest.java b/src/test/java/org/rootservices/jwt/jwk/PublicKeyFactoryTest.java new file mode 100644 index 0000000..f341e29 --- /dev/null +++ b/src/test/java/org/rootservices/jwt/jwk/PublicKeyFactoryTest.java @@ -0,0 +1,58 @@ +package org.rootservices.jwt.jwk; + +import helper.entity.Factory; +import org.junit.Before; +import org.junit.Test; +import org.rootservices.jwt.config.JwtAppFactory; +import org.rootservices.jwt.entity.jwk.RSAPublicKey; +import org.rootservices.jwt.jws.signer.factory.rsa.exception.PublicKeyException; + +import java.math.BigInteger; + +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.*; + +public class PublicKeyFactoryTest { + private JwtAppFactory appFactory; + private PublicKeyFactory subject; + + @Before + public void setUp() { + this.appFactory = new JwtAppFactory(); + this.subject = appFactory.publicKeyFactory(); + } + + @Test + public void makePublicKeyShouldBeRsaPublicKey() throws PublicKeyException { + + RSAPublicKey publicKey = Factory.makeRSAPublicKey(); + + // expected values + BigInteger modulus = new BigInteger("20446702916744654562596343388758805860065209639960173505037453331270270518732245089773723012043203236097095623402044690115755377345254696448759605707788965848889501746836211206270643833663949992536246985362693736387185145424787922241585721992924045675229348655595626434390043002821512765630397723028023792577935108185822753692574221566930937805031155820097146819964920270008811327036286786392793593121762425048860211859763441770446703722015857250621107855398693133264081150697423188751482418465308470313958250757758547155699749157985955379381294962058862159085915015369381046959790476428631998204940879604226680285601"); + BigInteger publicExponent = new BigInteger("65537"); + + java.security.interfaces.RSAPublicKey actual = subject.makePublicKey(publicKey); + + assertThat(actual, is(notNullValue())); + assertThat(actual.getAlgorithm(), is("RSA")); + assertThat(actual.getModulus(), is(modulus)); + assertThat(actual.getPublicExponent(), is(publicExponent)); + + } + + @Test + public void makePublicKeyWhenKeyIsNot512ShouldThrowPublicKeyException() throws PublicKeyException { + RSAPublicKey publicKey = Factory.makeRSAPublicKey(); + publicKey.setN(new BigInteger("1")); + + PublicKeyException actual = null; + try { + subject.makePublicKey(publicKey); + } catch (PublicKeyException e) { + actual = e; + } + assertThat(actual, is(notNullValue())); + } + +} \ No newline at end of file diff --git a/src/test/java/org/rootservices/jwt/jws/serialization/SecureJwtSerializerTest.java b/src/test/java/org/rootservices/jwt/jws/serialization/SecureJwtSerializerTest.java new file mode 100644 index 0000000..e965d1e --- /dev/null +++ b/src/test/java/org/rootservices/jwt/jws/serialization/SecureJwtSerializerTest.java @@ -0,0 +1,80 @@ +package org.rootservices.jwt.jws.serialization; + +import helper.entity.Claim; +import helper.entity.Factory; +import org.junit.Before; +import org.junit.Test; +import org.rootservices.jwt.config.JwtAppFactory; +import org.rootservices.jwt.entity.jwk.RSAKeyPair; +import org.rootservices.jwt.entity.jwk.SymmetricKey; +import org.rootservices.jwt.entity.jwt.header.Algorithm; + +import java.io.ByteArrayOutputStream; +import java.util.Optional; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.*; + + +public class SecureJwtSerializerTest { + private JwtAppFactory appFactory; + + @Before + public void setUp() { + appFactory = new JwtAppFactory(); + } + + @Test + public void compactJwtWithSymmetricKeyShouldEncode() throws Exception { + SymmetricKey key = Factory.makeSymmetricKey(); + key.setKeyId(Optional.of("test-key-id")); + + Claim claim = Factory.makeClaim(); + + SecureJwtSerializer subject = appFactory.secureJwtSerializer(Algorithm.HS256, key); + ByteArrayOutputStream actual = subject.compactJwt(claim); + + assertThat(actual.toString(), is("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6InRlc3Qta2V5LWlkIn0.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.YiFm03WWrDAbFn7omROmU2GHACkaGI30xdbWFzyoCNQ")); + + } + + @Test + public void compactJwtWithAsymmetricKeyShouldEncode() throws Exception { + RSAKeyPair key = Factory.makeRSAKeyPair(); + key.setKeyId(Optional.of("test-key-id")); + + Claim claim = Factory.makeClaim(); + + SecureJwtSerializer subject = appFactory.secureJwtSerializer(Algorithm.RS256, key); + ByteArrayOutputStream actual = subject.compactJwt(claim); + + assertThat(actual.toString(), is("eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6InRlc3Qta2V5LWlkIn0.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.JmMm15IjKsNB18oMqIIaIPHQ8TuqEXNdbmGyEya5Yuoo2Kj132PhiCt2gbPL2i75IH1Zmjvdc7Fm2eb2Db6P6NXezZEHgZG3WVTWJwl11lQnDnj6hTrTbHnL0XUgcFw0vIwthQF6NNjAy2lTMSG0KTH5y_3D-5pt6FM2cyfvK5RwhCom9v2MDWA7fTqR1u5L-_dfcgRlN5rjQ-QYBsk3oaNTMU9MtXtEuG7erun_-VXQJjXGwDRO_kPmzN-wILyoaOr670xpaHVmFLrTakjvfhCkLrB1YwdQV-B6ZFLqTpQpGr7ydEWMyuoiV0Xg71-mJhNHeml_jFMUwm-Lu-d2Og")); + } + + @Test + public void compactJwtToStringWithSymmetricKeyShouldEncode() throws Exception { + SymmetricKey key = Factory.makeSymmetricKey(); + key.setKeyId(Optional.of("test-key-id")); + + Claim claim = Factory.makeClaim(); + + SecureJwtSerializer subject = appFactory.secureJwtSerializer(Algorithm.HS256, key); + String actual = subject.compactJwtToString(claim); + + assertThat(actual, is("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6InRlc3Qta2V5LWlkIn0.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.YiFm03WWrDAbFn7omROmU2GHACkaGI30xdbWFzyoCNQ")); + + } + + @Test + public void compactJwtToStringWithAsymmetricKeyShouldEncode() throws Exception { + RSAKeyPair key = Factory.makeRSAKeyPair(); + key.setKeyId(Optional.of("test-key-id")); + + Claim claim = Factory.makeClaim(); + + SecureJwtSerializer subject = appFactory.secureJwtSerializer(Algorithm.RS256, key); + String actual = subject.compactJwtToString(claim); + + assertThat(actual, is("eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6InRlc3Qta2V5LWlkIn0.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.JmMm15IjKsNB18oMqIIaIPHQ8TuqEXNdbmGyEya5Yuoo2Kj132PhiCt2gbPL2i75IH1Zmjvdc7Fm2eb2Db6P6NXezZEHgZG3WVTWJwl11lQnDnj6hTrTbHnL0XUgcFw0vIwthQF6NNjAy2lTMSG0KTH5y_3D-5pt6FM2cyfvK5RwhCom9v2MDWA7fTqR1u5L-_dfcgRlN5rjQ-QYBsk3oaNTMU9MtXtEuG7erun_-VXQJjXGwDRO_kPmzN-wILyoaOr670xpaHVmFLrTakjvfhCkLrB1YwdQV-B6ZFLqTpQpGr7ydEWMyuoiV0Xg71-mJhNHeml_jFMUwm-Lu-d2Og")); + } +} \ No newline at end of file diff --git a/src/test/java/org/rootservices/jwt/signature/signer/MacSignerTest.java b/src/test/java/org/rootservices/jwt/jws/signer/MacSignerTest.java similarity index 81% rename from src/test/java/org/rootservices/jwt/signature/signer/MacSignerTest.java rename to src/test/java/org/rootservices/jwt/jws/signer/MacSignerTest.java index 29d5d95..cd4f480 100644 --- a/src/test/java/org/rootservices/jwt/signature/signer/MacSignerTest.java +++ b/src/test/java/org/rootservices/jwt/jws/signer/MacSignerTest.java @@ -1,19 +1,19 @@ -package org.rootservices.jwt.signature.signer; +package org.rootservices.jwt.jws.signer; import helper.entity.Claim; import helper.entity.Factory; import org.junit.Before; import org.junit.Test; -import org.rootservices.jwt.config.AppFactory; +import org.rootservices.jwt.config.JwtAppFactory; import org.rootservices.jwt.entity.jwk.SymmetricKey; import org.rootservices.jwt.entity.jwt.JsonWebToken; import org.rootservices.jwt.entity.jwt.header.Algorithm; import org.rootservices.jwt.entity.jwt.header.Header; import org.rootservices.jwt.entity.jwt.header.TokenType; -import org.rootservices.jwt.serializer.exception.JwtToJsonException; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidAlgorithmException; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidJsonWebKeyException; +import org.rootservices.jwt.serialization.exception.JwtToJsonException; +import org.rootservices.jwt.jws.signer.factory.exception.InvalidAlgorithmException; +import org.rootservices.jwt.jws.signer.factory.exception.InvalidJsonWebKeyException; import java.util.Optional; @@ -30,7 +30,7 @@ public class MacSignerTest { public void setUp() throws InvalidAlgorithmException, InvalidJsonWebKeyException { SymmetricKey key = Factory.makeSymmetricKey(); - AppFactory appFactory = new AppFactory(); + JwtAppFactory appFactory = new JwtAppFactory(); subject = appFactory.signerFactory().makeSigner(Algorithm.HS256, key); } @@ -59,8 +59,8 @@ public void shouldSignJwtCorrectly() throws JwtToJsonException { JsonWebToken jwt = new JsonWebToken(header, claim); - String actual = subject.run(jwt); - assertThat(actual, is("lliDzOlRAdGUCfCHCPx_uisb6ZfZ1LRQa0OJLeYTTpY")); + byte[] actual = subject.run(jwt); + assertThat(actual, is("lliDzOlRAdGUCfCHCPx_uisb6ZfZ1LRQa0OJLeYTTpY".getBytes())); } /** @@ -75,8 +75,8 @@ public void shouldSignBytesCorrectly() { String input = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9." + "eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ"; - String actual = subject.run(input.getBytes()); + byte[] actual = subject.run(input.getBytes()); - assertThat(actual, is("lliDzOlRAdGUCfCHCPx_uisb6ZfZ1LRQa0OJLeYTTpY")); + assertThat(actual, is("lliDzOlRAdGUCfCHCPx_uisb6ZfZ1LRQa0OJLeYTTpY".getBytes())); } } \ No newline at end of file diff --git a/src/test/java/org/rootservices/jwt/signature/signer/RSASignerTest.java b/src/test/java/org/rootservices/jwt/jws/signer/RSASignerTest.java similarity index 81% rename from src/test/java/org/rootservices/jwt/signature/signer/RSASignerTest.java rename to src/test/java/org/rootservices/jwt/jws/signer/RSASignerTest.java index 7528ee5..682746f 100644 --- a/src/test/java/org/rootservices/jwt/signature/signer/RSASignerTest.java +++ b/src/test/java/org/rootservices/jwt/jws/signer/RSASignerTest.java @@ -1,15 +1,16 @@ -package org.rootservices.jwt.signature.signer; +package org.rootservices.jwt.jws.signer; import helper.entity.Factory; import org.junit.Before; import org.junit.Test; -import org.rootservices.jwt.config.AppFactory; +import org.rootservices.jwt.config.JwtAppFactory; import org.rootservices.jwt.entity.jwk.RSAKeyPair; import org.rootservices.jwt.entity.jwt.JsonWebToken; import org.rootservices.jwt.entity.jwt.header.Algorithm; -import org.rootservices.jwt.serializer.exception.JwtToJsonException; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidAlgorithmException; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidJsonWebKeyException; +import org.rootservices.jwt.entity.jwt.header.TokenType; +import org.rootservices.jwt.serialization.exception.JwtToJsonException; +import org.rootservices.jwt.jws.signer.factory.exception.InvalidAlgorithmException; +import org.rootservices.jwt.jws.signer.factory.exception.InvalidJsonWebKeyException; import java.util.Optional; @@ -22,11 +23,11 @@ * Created by tommackenzie on 11/12/15. */ public class RSASignerTest { - private AppFactory appFactory; + private JwtAppFactory appFactory; @Before public void setUp() { - this.appFactory = new AppFactory(); + this.appFactory = new JwtAppFactory(); } /** @@ -52,10 +53,10 @@ public void signBytesWithRS256ShouldSignCorrectly() throws Exception { 98, 83, 57, 112, 99, 49, 57, 121, 98, 50, 57, 48, 73, 106, 112, 48, 99, 110, 86, 108, 102, 81}; - String actual = subject.run(signInput); + byte[] actual = subject.run(signInput); assertThat(actual, is(notNullValue())); - assertThat(actual, is(expected)); + assertThat(actual, is(expected.getBytes())); } /** @@ -74,11 +75,11 @@ public void signTokenWithRS256ShouldSignCorrectly() throws InvalidAlgorithmExcep RSAKeyPair jwk = Factory.makeRSAKeyPair(); Signer subject = appFactory.signerFactory().makeSigner(Algorithm.RS256, jwk); - JsonWebToken jwt = Factory.makeToken(Algorithm.RS256, Optional.empty()); + JsonWebToken jwt = Factory.makeToken(Algorithm.RS256, Optional.empty()); - String actual = subject.run(jwt); + byte[] actual = subject.run(jwt); assertThat(actual, is(notNullValue())); - assertThat(actual, is(expected)); + assertThat(actual, is(expected.getBytes())); } } \ No newline at end of file diff --git a/src/test/java/org/rootservices/jwt/signature/signer/factory/MacFactoryTest.java b/src/test/java/org/rootservices/jwt/jws/signer/factory/MacFactoryTest.java similarity index 72% rename from src/test/java/org/rootservices/jwt/signature/signer/factory/MacFactoryTest.java rename to src/test/java/org/rootservices/jwt/jws/signer/factory/MacFactoryTest.java index a9b4628..4fcab9a 100644 --- a/src/test/java/org/rootservices/jwt/signature/signer/factory/MacFactoryTest.java +++ b/src/test/java/org/rootservices/jwt/jws/signer/factory/MacFactoryTest.java @@ -1,15 +1,15 @@ -package org.rootservices.jwt.signature.signer.factory; +package org.rootservices.jwt.jws.signer.factory; import helper.entity.Factory; import org.junit.Before; import org.junit.Test; -import org.rootservices.jwt.config.AppFactory; +import org.rootservices.jwt.config.JwtAppFactory; import org.rootservices.jwt.entity.jwk.SymmetricKey; -import org.rootservices.jwt.signature.signer.SignAlgorithm; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidAlgorithmException; -import org.rootservices.jwt.signature.signer.factory.hmac.MacFactory; -import org.rootservices.jwt.signature.signer.factory.hmac.exception.SecurityKeyException; +import org.rootservices.jwt.jws.signer.SignAlgorithm; +import org.rootservices.jwt.jws.signer.factory.exception.InvalidAlgorithmException; +import org.rootservices.jwt.jws.signer.factory.hmac.MacFactory; +import org.rootservices.jwt.jws.signer.factory.hmac.exception.SecurityKeyException; import javax.crypto.Mac; import java.util.Base64; @@ -24,7 +24,7 @@ public class MacFactoryTest { @Before public void setUp() { - AppFactory appFactory = new AppFactory(); + JwtAppFactory appFactory = new JwtAppFactory(); subject = appFactory.macFactory(); } diff --git a/src/test/java/org/rootservices/jwt/signature/signer/factory/PrivateKeySignatureFactoryTest.java b/src/test/java/org/rootservices/jwt/jws/signer/factory/PrivateKeySignatureFactoryTest.java similarity index 85% rename from src/test/java/org/rootservices/jwt/signature/signer/factory/PrivateKeySignatureFactoryTest.java rename to src/test/java/org/rootservices/jwt/jws/signer/factory/PrivateKeySignatureFactoryTest.java index 2e74f02..9654ef4 100644 --- a/src/test/java/org/rootservices/jwt/signature/signer/factory/PrivateKeySignatureFactoryTest.java +++ b/src/test/java/org/rootservices/jwt/jws/signer/factory/PrivateKeySignatureFactoryTest.java @@ -1,15 +1,14 @@ -package org.rootservices.jwt.signature.signer.factory; +package org.rootservices.jwt.jws.signer.factory; import helper.entity.Factory; import org.junit.Before; import org.junit.Test; -import org.rootservices.jwt.config.AppFactory; +import org.rootservices.jwt.config.JwtAppFactory; import org.rootservices.jwt.entity.jwk.RSAKeyPair; -import org.rootservices.jwt.signature.signer.SignAlgorithm; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidAlgorithmException; -import org.rootservices.jwt.signature.signer.factory.rsa.PrivateKeySignatureFactory; -import org.rootservices.jwt.signature.signer.factory.rsa.exception.PrivateKeyException; -import org.rootservices.jwt.signature.signer.factory.rsa.exception.RSAPrivateKeyException; +import org.rootservices.jwt.jws.signer.SignAlgorithm; +import org.rootservices.jwt.jws.signer.factory.rsa.PrivateKeySignatureFactory; +import org.rootservices.jwt.jws.signer.factory.rsa.exception.PrivateKeyException; + import java.math.BigInteger; import java.security.*; @@ -28,7 +27,7 @@ public class PrivateKeySignatureFactoryTest { @Before public void setUp() { - AppFactory appFactory = new AppFactory(); + JwtAppFactory appFactory = new JwtAppFactory(); this.subject = appFactory.privateKeySignatureFactory(); } @@ -59,16 +58,23 @@ public void makePrivateKeyShouldMakeRSAPrivateCrtKey() throws Exception { assertThat(privateKey.getCrtCoefficient(), is(crtCoefficient)); } - @Test(expected = PrivateKeyException.class) + @Test public void makePrivateKeyWhenKeyIsNot512ShouldThrowPrivateKeyException() throws Exception { RSAKeyPair rsaKeyPair = Factory.makeRSAKeyPair(); - rsaKeyPair.setN(new BigInteger("12")); + rsaKeyPair.setN(new BigInteger("1")); + + PrivateKeyException actual = null; + try { + subject.makePrivateKey(rsaKeyPair); + } catch (PrivateKeyException e) { + actual = e; + } - subject.makePrivateKey(rsaKeyPair); + assertThat(actual, is(notNullValue())); } @Test - public void testMakeSignatureShouldBeRS256() throws InvalidAlgorithmException, PrivateKeyException, RSAPrivateKeyException { + public void testMakeSignatureShouldBeRS256() throws Exception { RSAKeyPair jwk = Factory.makeRSAKeyPair(); Signature signature = subject.makeSignature(SignAlgorithm.RS256, jwk); diff --git a/src/test/java/org/rootservices/jwt/signature/signer/factory/PublicKeySignatureFactoryTest.java b/src/test/java/org/rootservices/jwt/jws/signer/factory/PublicKeySignatureFactoryTest.java similarity index 68% rename from src/test/java/org/rootservices/jwt/signature/signer/factory/PublicKeySignatureFactoryTest.java rename to src/test/java/org/rootservices/jwt/jws/signer/factory/PublicKeySignatureFactoryTest.java index 946afd7..0fea11a 100644 --- a/src/test/java/org/rootservices/jwt/signature/signer/factory/PublicKeySignatureFactoryTest.java +++ b/src/test/java/org/rootservices/jwt/jws/signer/factory/PublicKeySignatureFactoryTest.java @@ -1,15 +1,16 @@ -package org.rootservices.jwt.signature.signer.factory; +package org.rootservices.jwt.jws.signer.factory; import helper.entity.Factory; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; -import org.rootservices.jwt.config.AppFactory; +import org.rootservices.jwt.config.JwtAppFactory; import org.rootservices.jwt.entity.jwk.RSAPublicKey; -import org.rootservices.jwt.signature.signer.SignAlgorithm; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidAlgorithmException; -import org.rootservices.jwt.signature.signer.factory.rsa.PublicKeySignatureFactory; -import org.rootservices.jwt.signature.signer.factory.rsa.exception.PublicKeyException; -import org.rootservices.jwt.signature.signer.factory.rsa.exception.RSAPublicKeyException; +import org.rootservices.jwt.jws.signer.SignAlgorithm; +import org.rootservices.jwt.jws.signer.factory.exception.InvalidAlgorithmException; +import org.rootservices.jwt.jws.signer.factory.rsa.PublicKeySignatureFactory; +import org.rootservices.jwt.jws.signer.factory.rsa.exception.PublicKeyException; +import org.rootservices.jwt.jws.signer.factory.rsa.exception.RSAPublicKeyException; import java.math.BigInteger; import java.security.Signature; @@ -22,17 +23,17 @@ * Created by tommackenzie on 11/14/15. */ public class PublicKeySignatureFactoryTest { - private AppFactory appFactory; + private JwtAppFactory appFactory; private PublicKeySignatureFactory subject; @Before public void setUp() { - this.appFactory = new AppFactory(); + this.appFactory = new JwtAppFactory(); this.subject = appFactory.publicKeySignatureFactory(); } @Test - public void makePublicKeyShouldBeRsaPublicKey() throws PublicKeyException { + public void makePublicKeyShouldBeRsaPublicKey() throws Exception { RSAPublicKey publicKey = Factory.makeRSAPublicKey(); @@ -49,16 +50,22 @@ public void makePublicKeyShouldBeRsaPublicKey() throws PublicKeyException { } - @Test(expected = PublicKeyException.class) - public void makePublicKeyWhenKeyIsNot512ShouldThrowPublicKeyException() throws PublicKeyException { + @Test + public void makePublicKeyWhenKeyIsNot512ShouldThrowPublicKeyException() throws Exception { RSAPublicKey publicKey = Factory.makeRSAPublicKey(); publicKey.setN(new BigInteger("1")); - subject.makePublicKey(publicKey); + PublicKeyException actual = null; + try { + subject.makePublicKey(publicKey); + } catch (PublicKeyException e) { + actual = e; + } + assertThat(actual, is(notNullValue())); } - @Test - public void testMakeSignatureShouldBeRS256() throws InvalidAlgorithmException, PublicKeyException, RSAPublicKeyException { + @Test + public void testMakeSignatureShouldBeRS256() throws Exception { RSAPublicKey publicKey = Factory.makeRSAPublicKey(); Signature signature = subject.makeSignature(SignAlgorithm.RS256, publicKey); diff --git a/src/test/java/org/rootservices/jwt/signature/signer/factory/SignerFactoryImplTest.java b/src/test/java/org/rootservices/jwt/jws/signer/factory/SignerFactoryImplTest.java similarity index 69% rename from src/test/java/org/rootservices/jwt/signature/signer/factory/SignerFactoryImplTest.java rename to src/test/java/org/rootservices/jwt/jws/signer/factory/SignerFactoryImplTest.java index 46ea893..b8018ef 100644 --- a/src/test/java/org/rootservices/jwt/signature/signer/factory/SignerFactoryImplTest.java +++ b/src/test/java/org/rootservices/jwt/jws/signer/factory/SignerFactoryImplTest.java @@ -1,17 +1,17 @@ -package org.rootservices.jwt.signature.signer.factory; +package org.rootservices.jwt.jws.signer.factory; import helper.entity.Factory; import org.junit.Before; import org.junit.Test; -import org.rootservices.jwt.config.AppFactory; +import org.rootservices.jwt.config.JwtAppFactory; import org.rootservices.jwt.entity.jwk.RSAKeyPair; import org.rootservices.jwt.entity.jwk.SymmetricKey; import org.rootservices.jwt.entity.jwt.header.Algorithm; -import org.rootservices.jwt.signature.signer.MacSigner; -import org.rootservices.jwt.signature.signer.RSASigner; -import org.rootservices.jwt.signature.signer.Signer; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidAlgorithmException; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidJsonWebKeyException; +import org.rootservices.jwt.jws.signer.MacSigner; +import org.rootservices.jwt.jws.signer.RSASigner; +import org.rootservices.jwt.jws.signer.Signer; +import org.rootservices.jwt.jws.signer.factory.exception.InvalidAlgorithmException; +import org.rootservices.jwt.jws.signer.factory.exception.InvalidJsonWebKeyException; import static org.hamcrest.core.IsInstanceOf.instanceOf; import static org.junit.Assert.*; @@ -24,7 +24,7 @@ public class SignerFactoryImplTest { @Before public void setUp() throws Exception { - AppFactory appFactory = new AppFactory(); + JwtAppFactory appFactory = new JwtAppFactory(); subject = appFactory.signerFactory(); } diff --git a/src/test/java/org/rootservices/jwt/signature/verifier/VerifyMacSignatureTest.java b/src/test/java/org/rootservices/jwt/jws/verifier/VerifyMacSignatureTest.java similarity index 61% rename from src/test/java/org/rootservices/jwt/signature/verifier/VerifyMacSignatureTest.java rename to src/test/java/org/rootservices/jwt/jws/verifier/VerifyMacSignatureTest.java index d1d1a59..b0c1cbc 100644 --- a/src/test/java/org/rootservices/jwt/signature/verifier/VerifyMacSignatureTest.java +++ b/src/test/java/org/rootservices/jwt/jws/verifier/VerifyMacSignatureTest.java @@ -1,37 +1,33 @@ -package org.rootservices.jwt.signature.verifier; +package org.rootservices.jwt.jws.verifier; import helper.entity.Claim; import helper.entity.Factory; import org.junit.Before; import org.junit.Test; -import org.rootservices.jwt.config.AppFactory; +import org.rootservices.jwt.config.JwtAppFactory; import org.rootservices.jwt.entity.jwk.SymmetricKey; import org.rootservices.jwt.entity.jwt.JsonWebToken; import org.rootservices.jwt.entity.jwt.header.Algorithm; -import org.rootservices.jwt.serializer.JWTSerializer; -import org.rootservices.jwt.serializer.exception.JsonToJwtException; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidAlgorithmException; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidJsonWebKeyException; +import org.rootservices.jwt.serialization.JwtSerde; +import org.rootservices.jwt.serialization.exception.JsonToJwtException; import static org.junit.Assert.assertTrue; -/** - * Created by tommackenzie on 8/30/15. - */ + public class VerifyMacSignatureTest { - private AppFactory appFactory; - private JWTSerializer jwtSerializer; + private JwtAppFactory appFactory; + private JwtSerde jwtSerde; @Before public void setUp() { - appFactory = new AppFactory(); - jwtSerializer = appFactory.jwtSerializer(); + appFactory = new JwtAppFactory(); + jwtSerde = appFactory.jwtSerde(); } @Test - public void verifySecureJwtWithJwtShouldBeTrue() throws InvalidAlgorithmException, InvalidJsonWebKeyException { + public void verifySecureJwtWithJwtShouldBeTrue() throws Exception { String jwtAsText = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9." + "eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ." + @@ -39,7 +35,7 @@ public void verifySecureJwtWithJwtShouldBeTrue() throws InvalidAlgorithmExceptio JsonWebToken jwt = null; try { - jwt = jwtSerializer.stringToJwt(jwtAsText, Claim.class); + jwt = jwtSerde.stringToJwt(jwtAsText, Claim.class); } catch (JsonToJwtException e) { e.printStackTrace(); } @@ -53,14 +49,14 @@ public void verifySecureJwtWithJwtShouldBeTrue() throws InvalidAlgorithmExceptio } @Test - public void verifyUnsecureJwtWithJwtShouldBeTrue() throws InvalidAlgorithmException, InvalidJsonWebKeyException { + public void verifyUnsecureJwtWithJwtShouldBeTrue() throws Exception { String jwtAsText = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9." + "eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ."; JsonWebToken jwt = null; try { - jwt = jwtSerializer.stringToJwt(jwtAsText, Claim.class); + jwt = jwtSerde.stringToJwt(jwtAsText, Claim.class); } catch (JsonToJwtException e) { e.printStackTrace(); } diff --git a/src/test/java/org/rootservices/jwt/signature/verifier/VerifyRsaSignatureTest.java b/src/test/java/org/rootservices/jwt/jws/verifier/VerifyRsaSignatureTest.java similarity index 82% rename from src/test/java/org/rootservices/jwt/signature/verifier/VerifyRsaSignatureTest.java rename to src/test/java/org/rootservices/jwt/jws/verifier/VerifyRsaSignatureTest.java index a2877ec..77ed0e4 100644 --- a/src/test/java/org/rootservices/jwt/signature/verifier/VerifyRsaSignatureTest.java +++ b/src/test/java/org/rootservices/jwt/jws/verifier/VerifyRsaSignatureTest.java @@ -1,14 +1,14 @@ -package org.rootservices.jwt.signature.verifier; +package org.rootservices.jwt.jws.verifier; import helper.entity.Claim; import helper.entity.Factory; import org.junit.Before; import org.junit.Test; -import org.rootservices.jwt.config.AppFactory; +import org.rootservices.jwt.config.JwtAppFactory; import org.rootservices.jwt.entity.jwk.RSAPublicKey; import org.rootservices.jwt.entity.jwt.JsonWebToken; import org.rootservices.jwt.entity.jwt.header.Algorithm; -import org.rootservices.jwt.serializer.JWTSerializer; +import org.rootservices.jwt.serialization.JwtSerde; import static org.hamcrest.core.Is.is; import static org.junit.Assert.*; @@ -17,17 +17,17 @@ * Created by tommackenzie on 11/14/15. */ public class VerifyRsaSignatureTest { - private AppFactory appFactory; + private JwtAppFactory appFactory; @Before public void setUp() { - this.appFactory = new AppFactory(); + this.appFactory = new JwtAppFactory(); } @Test public void testRunShouldBeTrue() throws Exception { String jwtAsText = "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.cC4hiUPoj9Eetdgtv3hF80EGrhuB__dzERat0XF9g2VtQgr9PJbu3XOiZj5RZmh7AAuHIm4Bh-0Qc_lF5YKt_O8W2Fp5jujGbds9uJdbF9CUAr7t1dnZcAcQjbKBYNX4BAynRFdiuB--f_nZLgrnbyTyWzO75vRK5h6xBArLIARNPvkSjtQBMHlb1L07Qe7K0GarZRmB_eSN9383LcOLn6_dO--xi12jzDwusC-eOkHWEsqtFZESc6BfI7noOPqvhJ1phCnvWh6IeYI2w9QOYEUipUTI8np6LbgGY9Fs98rqVt5AXLIhWkWywlVmtVrBp0igcN_IoypGlUPQGe77Rw"; - JWTSerializer serializer = appFactory.jwtSerializer(); + JwtSerde serializer = appFactory.jwtSerde(); JsonWebToken jwt = serializer.stringToJwt(jwtAsText, Claim.class); RSAPublicKey publicKey = Factory.makeRSAPublicKey(); diff --git a/src/test/java/org/rootservices/jwt/signature/verifier/factory/VerifySignatureFactoryImplTest.java b/src/test/java/org/rootservices/jwt/jws/verifier/factory/VerifySignatureFactoryImplTest.java similarity index 77% rename from src/test/java/org/rootservices/jwt/signature/verifier/factory/VerifySignatureFactoryImplTest.java rename to src/test/java/org/rootservices/jwt/jws/verifier/factory/VerifySignatureFactoryImplTest.java index 2253eb2..ffba961 100644 --- a/src/test/java/org/rootservices/jwt/signature/verifier/factory/VerifySignatureFactoryImplTest.java +++ b/src/test/java/org/rootservices/jwt/jws/verifier/factory/VerifySignatureFactoryImplTest.java @@ -1,15 +1,15 @@ -package org.rootservices.jwt.signature.verifier.factory; +package org.rootservices.jwt.jws.verifier.factory; import helper.entity.Factory; import org.junit.Before; import org.junit.Test; -import org.rootservices.jwt.config.AppFactory; +import org.rootservices.jwt.config.JwtAppFactory; import org.rootservices.jwt.entity.jwk.RSAPublicKey; import org.rootservices.jwt.entity.jwk.SymmetricKey; import org.rootservices.jwt.entity.jwt.header.Algorithm; -import org.rootservices.jwt.signature.verifier.VerifyMacSignature; -import org.rootservices.jwt.signature.verifier.VerifyRsaSignature; -import org.rootservices.jwt.signature.verifier.VerifySignature; +import org.rootservices.jwt.jws.verifier.VerifyMacSignature; +import org.rootservices.jwt.jws.verifier.VerifyRsaSignature; +import org.rootservices.jwt.jws.verifier.VerifySignature; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.core.Is.is; @@ -19,11 +19,11 @@ * Created by tommackenzie on 11/15/15. */ public class VerifySignatureFactoryImplTest { - private AppFactory appFactory; + private JwtAppFactory appFactory; @Before public void setUp() { - this.appFactory = new AppFactory(); + this.appFactory = new JwtAppFactory(); } @Test diff --git a/src/test/java/org/rootservices/jwt/serialization/HeaderDeserializerTest.java b/src/test/java/org/rootservices/jwt/serialization/HeaderDeserializerTest.java new file mode 100644 index 0000000..5105c6f --- /dev/null +++ b/src/test/java/org/rootservices/jwt/serialization/HeaderDeserializerTest.java @@ -0,0 +1,40 @@ +package org.rootservices.jwt.serialization; + +import helper.entity.Factory; +import org.junit.Before; +import org.junit.Test; +import org.rootservices.jwt.config.JwtAppFactory; +import org.rootservices.jwt.entity.jwe.EncryptionAlgorithm; +import org.rootservices.jwt.entity.jwt.header.Algorithm; +import org.rootservices.jwt.entity.jwt.header.AlgorithmFor; +import org.rootservices.jwt.entity.jwt.header.Header; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.*; + +public class HeaderDeserializerTest { + private HeaderDeserializer subject; + + @Before + public void setUp() { + JwtAppFactory jwtAppFactory = new JwtAppFactory(); + subject = jwtAppFactory.headerDeserializer(); + } + + @Test + public void toHeader() throws Exception { + // https://tools.ietf.org/html/rfc7516#section-3.3 + String compactJWE = Factory.compactJWE(); + Header actual = subject.toHeader(compactJWE); + + assertThat(actual, is(notNullValue())); + + assertThat(actual.getKeyId().isPresent(), is(false)); + assertThat(actual.getType().isPresent(), is(false)); + assertThat(actual.getAlgorithm(), is(Algorithm.RSAES_OAEP)); + assertThat(actual.getAlgorithm().getAlgorithmFor(), is(AlgorithmFor.JWE)); + assertThat(actual.getEncryptionAlgorithm().isPresent(), is(true)); + assertThat(actual.getEncryptionAlgorithm().get(), is(EncryptionAlgorithm.AES_GCM_256)); + } +} \ No newline at end of file diff --git a/src/test/java/org/rootservices/jwt/serializer/JWTSerializerTest.java b/src/test/java/org/rootservices/jwt/serialization/JwtSerdeTest.java similarity index 79% rename from src/test/java/org/rootservices/jwt/serializer/JWTSerializerTest.java rename to src/test/java/org/rootservices/jwt/serialization/JwtSerdeTest.java index c89849c..d57ea63 100644 --- a/src/test/java/org/rootservices/jwt/serializer/JWTSerializerTest.java +++ b/src/test/java/org/rootservices/jwt/serialization/JwtSerdeTest.java @@ -1,21 +1,17 @@ -package org.rootservices.jwt.serializer; +package org.rootservices.jwt.serialization; import helper.entity.Claim; import helper.entity.Factory; -import org.junit.Before; import org.junit.Test; import org.rootservices.jwt.factory.SecureJwtFactory; import org.rootservices.jwt.factory.UnSecureJwtFactory; -import org.rootservices.jwt.config.AppFactory; +import org.rootservices.jwt.config.JwtAppFactory; import org.rootservices.jwt.entity.jwk.SymmetricKey; import org.rootservices.jwt.entity.jwt.JsonWebToken; import org.rootservices.jwt.entity.jwt.header.Algorithm; import org.rootservices.jwt.entity.jwt.header.TokenType; -import org.rootservices.jwt.serializer.exception.JsonToJwtException; -import org.rootservices.jwt.serializer.exception.JwtToJsonException; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidAlgorithmException; -import org.rootservices.jwt.signature.signer.factory.exception.InvalidJsonWebKeyException; +import java.io.ByteArrayOutputStream; import java.util.Optional; import static org.hamcrest.CoreMatchers.instanceOf; @@ -25,39 +21,32 @@ import static org.junit.Assert.assertThat; -/** - * Created by tommackenzie on 8/13/15. - */ -public class JWTSerializerTest { - private AppFactory appFactory; +public class JwtSerdeTest { - @Before - public void setUp() throws InvalidAlgorithmException, InvalidJsonWebKeyException { - appFactory = new AppFactory(); - } + private static JwtAppFactory appFactory = new JwtAppFactory(); @Test - public void UnsecuredJwtToStringShouldBeValidJWT() throws JwtToJsonException { + public void UnsecuredJwtToStringShouldBeValidJWT() throws Exception { UnSecureJwtFactory unsecureTokenBuilder = appFactory.unsecureJwtFactory(); - JWTSerializer subject = appFactory.jwtSerializer(); + JwtSerde subject = appFactory.jwtSerde(); String expectedJwt = "eyJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ."; Claim claim = Factory.makeClaim(); JsonWebToken tokenToMarshal = unsecureTokenBuilder.makeJwt(claim); - String actual = subject.jwtToString(tokenToMarshal); - assertThat(actual, is(expectedJwt)); + ByteArrayOutputStream actual = subject.compactJwt(tokenToMarshal); + assertThat(actual.toString(), is(expectedJwt)); } @Test - public void SecuredJwtToStringShouldBeValid() throws JwtToJsonException, InvalidAlgorithmException, InvalidJsonWebKeyException { + public void SecuredJwtToStringShouldBeValid() throws Exception { SymmetricKey key = Factory.makeSymmetricKey(); SecureJwtFactory secureJwtFactory = appFactory.secureJwtFactory(Algorithm.HS256, key); - JWTSerializer subject = appFactory.jwtSerializer(); + JwtSerde subject = appFactory.jwtSerde(); String signature = "lliDzOlRAdGUCfCHCPx_uisb6ZfZ1LRQa0OJLeYTTpY"; @@ -68,18 +57,18 @@ public void SecuredJwtToStringShouldBeValid() throws JwtToJsonException, Invalid Claim claim = Factory.makeClaim(); JsonWebToken tokenToMarshal = secureJwtFactory.makeJwt(claim); - String actual = subject.jwtToString(tokenToMarshal); + ByteArrayOutputStream actual = subject.compactJwt(tokenToMarshal); - assertThat(actual, is(expectedJwt)); + assertThat(actual.toString(), is(expectedJwt)); } @Test - public void SecuredJwtWithKeyIdToStringShouldBeValid() throws JwtToJsonException, InvalidAlgorithmException, InvalidJsonWebKeyException { + public void SecuredJwtWithKeyIdToStringShouldBeValid() throws Exception { SymmetricKey key = Factory.makeSymmetricKey(); key.setKeyId(Optional.of("test-key-id")); SecureJwtFactory secureJwtFactory = appFactory.secureJwtFactory(Algorithm.HS256, key); - JWTSerializer subject = appFactory.jwtSerializer(); + JwtSerde subject = appFactory.jwtSerde(); String signature = "YiFm03WWrDAbFn7omROmU2GHACkaGI30xdbWFzyoCNQ"; @@ -90,15 +79,15 @@ public void SecuredJwtWithKeyIdToStringShouldBeValid() throws JwtToJsonException Claim claim = Factory.makeClaim(); JsonWebToken tokenToMarshal = secureJwtFactory.makeJwt(claim); - String actual = subject.jwtToString(tokenToMarshal); + ByteArrayOutputStream actual = subject.compactJwt(tokenToMarshal); - assertThat(actual, is(expectedJwt)); + assertThat(actual.toString(), is(expectedJwt)); } @Test - public void stringToJwtShouldBeUnsecuredJwt() throws JsonToJwtException { + public void stringToJwtShouldBeUnsecuredJwt() throws Exception { - JWTSerializer subject = appFactory.jwtSerializer(); + JwtSerde subject = appFactory.jwtSerde(); String jwtAsText = "eyJhbGciOiJub25lIn0=." + "eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ==."; @@ -129,9 +118,9 @@ public void stringToJwtShouldBeUnsecuredJwt() throws JsonToJwtException { } @Test - public void stringToJwtShouldBeSecuredJwt() throws JsonToJwtException { + public void stringToJwtShouldBeSecuredJwt() throws Exception { - JWTSerializer subject = appFactory.jwtSerializer(); + JwtSerde subject = appFactory.jwtSerde(); String signature = "lliDzOlRAdGUCfCHCPx_uisb6ZfZ1LRQa0OJLeYTTpY"; @@ -164,16 +153,16 @@ public void stringToJwtShouldBeSecuredJwt() throws JsonToJwtException { assertThat(actual.getClaims().getJwtId().isPresent(), is(false)); assertThat(actual.getSignature().isPresent(), is(true)); - assertThat(actual.getSignature().get(), is(signature)); + assertThat(actual.getSignature().get(), is(signature.getBytes())); assertThat(actual.getJwt().isPresent(), is(true)); assertThat(actual.getJwt().get(), is(jwtAsText)); } @Test - public void stringToJwtShouldBeSecuredJwtWithKeyId() throws JsonToJwtException { + public void stringToJwtShouldBeSecuredJwtWithKeyId() throws Exception { - JWTSerializer subject = appFactory.jwtSerializer(); + JwtSerde subject = appFactory.jwtSerde(); String signature = "YiFm03WWrDAbFn7omROmU2GHACkaGI30xdbWFzyoCNQ"; @@ -207,7 +196,7 @@ public void stringToJwtShouldBeSecuredJwtWithKeyId() throws JsonToJwtException { assertThat(actual.getClaims().getJwtId().isPresent(), is(false)); assertThat(actual.getSignature().isPresent(), is(true)); - assertThat(actual.getSignature().get(), is(signature)); + assertThat(actual.getSignature().get(), is(signature.getBytes())); assertThat(actual.getJwt().isPresent(), is(true)); assertThat(actual.getJwt().get(), is(jwtAsText)); diff --git a/src/test/java/org/rootservices/jwt/serializer/SerializerImplTest.java b/src/test/java/org/rootservices/jwt/serialization/SerdesTest.java similarity index 71% rename from src/test/java/org/rootservices/jwt/serializer/SerializerImplTest.java rename to src/test/java/org/rootservices/jwt/serialization/SerdesTest.java index 4ea56a4..e31f5c2 100644 --- a/src/test/java/org/rootservices/jwt/serializer/SerializerImplTest.java +++ b/src/test/java/org/rootservices/jwt/serialization/SerdesTest.java @@ -1,14 +1,15 @@ -package org.rootservices.jwt.serializer; +package org.rootservices.jwt.serialization; import helper.entity.Claim; import org.junit.Before; import org.junit.Test; -import org.rootservices.jwt.config.AppFactory; +import org.rootservices.jwt.config.JwtAppFactory; import org.rootservices.jwt.entity.jwt.header.Header; import org.rootservices.jwt.entity.jwt.header.Algorithm; -import org.rootservices.jwt.serializer.exception.JsonException; +import org.rootservices.jwt.serialization.exception.JsonException; +import java.nio.charset.StandardCharsets; import java.util.Optional; import static org.hamcrest.CoreMatchers.notNullValue; @@ -17,30 +18,30 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; -/** - * Created by tommackenzie on 8/12/15. - */ -public class SerializerImplTest { - private AppFactory appFactory; +public class SerdesTest { + + private JwtAppFactory appFactory; @Before public void setUp() { - appFactory = new AppFactory(); + appFactory = new JwtAppFactory(); } @Test public void headerToJson() throws JsonException { - Serializer subject = appFactory.serializer(); + Serdes subject = appFactory.serdes(); Header header = new Header(); header.setAlgorithm(Algorithm.NONE); - String json = subject.objectToJson(header); - assertThat(json, is("{\"alg\":\"none\"}")); + + byte[] actual = subject.objectToByte(header); + String actualAsString = new String(actual, StandardCharsets.UTF_8); + assertThat(actualAsString, is("{\"alg\":\"none\"}")); } @Test public void claimToJsonExpectExcludesNullAndOptionalEmpty() throws JsonException { - Serializer subject = appFactory.serializer(); + Serdes subject = appFactory.serdes(); Claim claim = new Claim(); Optional issuer = Optional.of("joe"); @@ -50,13 +51,14 @@ public void claimToJsonExpectExcludesNullAndOptionalEmpty() throws JsonException claim.setIssuer(issuer); claim.setExpirationTime(expirationTime); - String json = subject.objectToJson(claim); - assertThat(json, is("{\"iss\":\"joe\",\"exp\":1300819380,\"http://example.com/is_root\":true}")); + byte[] actual = subject.objectToByte(claim); + String actualAsString = new String(actual, StandardCharsets.UTF_8); + assertThat(actualAsString, is("{\"iss\":\"joe\",\"exp\":1300819380,\"http://example.com/is_root\":true}")); } @Test public void jsonToUnsecuredHeader() throws JsonException { - Serializer subject = appFactory.serializer(); + Serdes subject = appFactory.serdes(); byte[] json = "{\"alg\":\"none\"}".getBytes(); Header actual = (Header) subject.jsonBytesToObject(json, Header.class); assertThat(actual.getAlgorithm(), is(Algorithm.NONE)); @@ -64,7 +66,7 @@ public void jsonToUnsecuredHeader() throws JsonException { @Test public void jsonToClaim() throws JsonException { - Serializer subject = appFactory.serializer(); + Serdes subject = appFactory.serdes(); byte[] json = "{\"iss\":\"joe\",\"exp\":1300819380,\"http://example.com/is_root\":true}".getBytes(); Claim actual = (Claim) subject.jsonBytesToObject(json, Claim.class); @@ -83,7 +85,7 @@ public void jsonToClaim() throws JsonException { @Test(expected=JsonException.class) public void jsonBytesToObjectShouldThrowJsonException() throws JsonException { - Serializer subject = appFactory.serializer(); + Serdes subject = appFactory.serdes(); byte[] invalidJson = "{\"iss\":\"joe\"".getBytes(); subject.jsonBytesToObject(invalidJson, Claim.class); diff --git a/src/test/java/org/rootservices/jwt/serialization/UnSecureJwtSerializerTest.java b/src/test/java/org/rootservices/jwt/serialization/UnSecureJwtSerializerTest.java new file mode 100644 index 0000000..e48e536 --- /dev/null +++ b/src/test/java/org/rootservices/jwt/serialization/UnSecureJwtSerializerTest.java @@ -0,0 +1,45 @@ +package org.rootservices.jwt.serialization; + +import helper.entity.Factory; +import org.junit.Before; +import org.junit.Test; +import org.rootservices.jwt.config.JwtAppFactory; +import org.rootservices.jwt.entity.jwt.Claims; + +import java.io.ByteArrayOutputStream; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.*; + + +public class UnSecureJwtSerializerTest { + private JwtAppFactory appFactory; + + @Before + public void setUp() { + appFactory = new JwtAppFactory(); + } + + @Test + public void compactJwtShouldBeOk() { + UnSecureJwtSerializer subject = appFactory.unSecureJwtSerializer(); + + Claims claims = Factory.makeClaim(); + + ByteArrayOutputStream actual = subject.compactJwt(claims); + + assertThat(actual.toString(), is("eyJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.")); + } + + @Test + public void compactJwtToStringShouldBeOk() { + UnSecureJwtSerializer subject = appFactory.unSecureJwtSerializer(); + + Claims claims = Factory.makeClaim(); + + String jwt = subject.compactJwtToString(claims); + + assertThat(jwt, is("eyJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLCJleHAiOjEzMDA4MTkzODAsImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.")); + } + +} \ No newline at end of file diff --git a/src/test/java/org/rootservices/jwt/translator/CSRToRSAPublicKeyTest.java b/src/test/java/org/rootservices/jwt/translator/CSRToRSAPublicKeyTest.java deleted file mode 100644 index ce2e23b..0000000 --- a/src/test/java/org/rootservices/jwt/translator/CSRToRSAPublicKeyTest.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.rootservices.jwt.translator; - -import org.junit.Before; -import org.junit.Test; -import org.rootservices.jwt.config.AppFactory; -import org.rootservices.jwt.entity.jwk.KeyType; -import org.rootservices.jwt.entity.jwk.RSAPublicKey; -import org.rootservices.jwt.entity.jwk.Use; -import org.rootservices.jwt.translator.exception.InvalidKeyException; -import org.rootservices.jwt.translator.exception.InvalidCsrException; - -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.math.BigInteger; -import java.net.URL; -import java.util.Optional; - -import static org.hamcrest.core.Is.is; -import static org.hamcrest.core.IsNull.notNullValue; -import static org.junit.Assert.*; - -/** - * Created by tommackenzie on 12/1/15. - */ -public class CSRToRSAPublicKeyTest { - private AppFactory appFactory; - - @Before - public void setUp() { - appFactory = new AppFactory(); - } - - @Test - public void shouldTranslateCSRToRSAPublicKey() throws FileNotFoundException, InvalidCsrException, InvalidKeyException { - URL privateKeyURL = getClass().getResource("/certs/rsa-cert.csr"); - FileReader fr = new FileReader(privateKeyURL.getFile()); - - CSRToRSAPublicKey subject = appFactory.csrToRSAPublicKey(); - - RSAPublicKey actual = subject.translate(fr, Optional.of("test-key-id"), Use.SIGNATURE); - - assertThat(actual, is(notNullValue())); - assertThat(actual.getKeyId().isPresent(), is(true)); - assertThat(actual.getKeyId().get(), is("test-key-id")); - assertThat(actual.getUse(), is(Use.SIGNATURE)); - assertThat(actual.getKeyType(), is(KeyType.RSA)); - assertThat(actual.getN(), is(new BigInteger("31547363068675167897756930554362079780191578737192115507526898964667457901907675194501789280350861000129589859093278343756085398379306366123730728103421370791175356895018543806044325144818946471653951140470823139449286798248410821533402163473721370921654197140946196794921284894039254456107355893831146589487500059843522247062489436603543693162592270480345794243004091939582347569432019753837113712433864529566521319428801714421137033495634109852983552061952143849954383008111368867567356581104016991597045919263898215285259909976858081430303755638022211078978491982452596141052654560597952703737488015089139469137261"))); - assertThat(actual.getE(), is(new BigInteger("65537"))); - } - - @Test(expected = InvalidCsrException.class) - public void closedFileReaderShouldThrowInvalidFileReader() throws IOException, InvalidCsrException, InvalidKeyException { - URL privateKeyURL = getClass().getResource("/certs/rsa-cert-bad.csr"); - FileReader fr = new FileReader(privateKeyURL.getFile()); - fr.close(); - - CSRToRSAPublicKey subject = appFactory.csrToRSAPublicKey(); - - subject.translate(fr, Optional.of("test-key-id"), Use.SIGNATURE); - } - - @Test(expected = InvalidCsrException.class) - public void emptyFileShouldThrowInvalidFileReader() throws FileNotFoundException, InvalidCsrException, InvalidKeyException { - URL privateKeyURL = getClass().getResource("/certs/rsa-cert-bad.csr"); - FileReader fr = new FileReader(privateKeyURL.getFile()); - - CSRToRSAPublicKey subject = appFactory.csrToRSAPublicKey(); - - subject.translate(fr, Optional.of("test-key-id"), Use.SIGNATURE); - } - - @Test(expected = InvalidCsrException.class) - public void pemFileShouldThrowInvalidFileReader() throws FileNotFoundException, InvalidCsrException, InvalidKeyException { - URL privateKeyURL = getClass().getResource("/certs/rsa-private-key.pem"); - FileReader fr = new FileReader(privateKeyURL.getFile()); - - CSRToRSAPublicKey subject = appFactory.csrToRSAPublicKey(); - - subject.translate(fr, Optional.of("test-key-id"), Use.SIGNATURE); - } - -} \ No newline at end of file diff --git a/src/test/java/org/rootservices/jwt/translator/PemToRSAKeyPairTest.java b/src/test/java/org/rootservices/jwt/translator/PemToRSAKeyPairTest.java deleted file mode 100644 index b233191..0000000 --- a/src/test/java/org/rootservices/jwt/translator/PemToRSAKeyPairTest.java +++ /dev/null @@ -1,118 +0,0 @@ -package org.rootservices.jwt.translator; - -import org.junit.Before; -import org.junit.Test; -import org.rootservices.jwt.config.AppFactory; -import org.rootservices.jwt.entity.jwk.KeyType; -import org.rootservices.jwt.entity.jwk.RSAKeyPair; -import org.rootservices.jwt.entity.jwk.Use; -import org.rootservices.jwt.translator.exception.InvalidKeyException; -import org.rootservices.jwt.translator.exception.InvalidPemException; - -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.math.BigInteger; -import java.net.URL; -import java.util.Optional; - -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.*; - -/** - * Created by tommackenzie on 11/30/15. - */ -public class PemToRSAKeyPairTest { - - private AppFactory appFactory; - - @Before - public void setUp() { - this.appFactory = new AppFactory(); - } - - private FileReader makeFileReader(String filePath) { - - URL privateKeyURL = getClass().getResource(filePath); - - if (privateKeyURL == null) { - fail("Could not find file the pem file"); - } - - FileReader pemFileReader = null; - try { - pemFileReader = new FileReader(privateKeyURL.getFile()); - } catch (FileNotFoundException e) { - fail("Could not find file the pem file"); - } - - return pemFileReader; - } - - @Test - public void shouldMakeCorrectKeyPair() throws InvalidPemException, InvalidKeyException { - - PemToRSAKeyPair pemToRSAKeyPair = appFactory.pemToRSAKeyPair(); - - FileReader pemFileReader = makeFileReader("/certs/rsa-private-key.pem"); - - // expected - BigInteger modulus = new BigInteger("31547363068675167897756930554362079780191578737192115507526898964667457901907675194501789280350861000129589859093278343756085398379306366123730728103421370791175356895018543806044325144818946471653951140470823139449286798248410821533402163473721370921654197140946196794921284894039254456107355893831146589487500059843522247062489436603543693162592270480345794243004091939582347569432019753837113712433864529566521319428801714421137033495634109852983552061952143849954383008111368867567356581104016991597045919263898215285259909976858081430303755638022211078978491982452596141052654560597952703737488015089139469137261"); - BigInteger publicExponent = new BigInteger("65537"); - BigInteger privateExponent = new BigInteger("17926596396547475894233270530768851383098319785033974298729103320920713485892606190677649794612912011624365716198373114421172411325567975049420267105597071419719570107380343773454639558084782421393484511379433366437751036110427199974448479025967889505063154488700692964884928677524388897872866332639054734563540603538126904942970545933364201807568104872067768314855737491966908061964979181796120872344579985695190632663663576855846805589958978811239981840087025695582715666984680745947985390068749640688608533968405297323218578662269674742653843895867705344639568613274268304462852744075002084615909877427512082671809"); - BigInteger primeP = new BigInteger("177896497866913720666018635152384129022597163894037528397616765963660310944144586061003646473127224648491803487187299104582675895481985461698392379397626497276548015737035578624405241545087536057660433797241365357543813340937549961569784412712933089949857152189846777292464517821447558299649089116062107231697"); - BigInteger primeQ = new BigInteger("177335492530471784736855608763756232554907628078583812409958753247718335607210292037747143084156694233415555712874052909486016311004636559265753924014644550889364310406206169714329162148665359467600692075303825823321048442016831954507581831805295679970247348504587073016601516999984331832595091571024265531613"); - BigInteger primeExponentP = new BigInteger("142329141845884828866167525452494154770142967966491657598007804851283469552241897333150208266657810049575342540048809699096510793959174599061499702783696961383623276273795314548912285200346672347641289435350317395630747649705044397591438056306970621762223017805551458268658689403692284844954763549012016579745"); - BigInteger primeExponentQ = new BigInteger("1279882935851704444520388527782118467407286083909396879166127382794006023196216917677867444021028066167288064027792346707766387156952455750685896608922087867474393378124349882888714675623216122620430098289801327714586507058210804804646019903930678191341181253988886972807002419106651036159993260495513642621"); - BigInteger crtCoefficient = new BigInteger("52655246168149931266593527226554483262446108013405644846090346118573657005660216425771053079024891453912366463810544032383603524938201963417881747736294434635848257983482194424189814343462587544169753320024624881614416412658658522200837842119558010863255094195173449128914773351492908487605687200685726121916"); - - RSAKeyPair actual = pemToRSAKeyPair.translate(pemFileReader, Optional.of("test-key-id"), Use.SIGNATURE); - - assertThat(actual, is(notNullValue())); - - assertThat(actual, is(notNullValue())); - assertThat(actual.getKeyId().isPresent(), is(true)); - assertThat(actual.getKeyId().get(), is("test-key-id")); - assertThat(actual.getKeyType(), is(KeyType.RSA)); - assertThat(actual.getUse(), is(Use.SIGNATURE)); - - assertThat(actual.getN(), is(modulus)); - assertThat(actual.getE(), is(publicExponent)); - assertThat(actual.getD(), is(privateExponent)); - assertThat(actual.getP(), is(primeP)); - assertThat(actual.getQ(), is(primeQ)); - assertThat(actual.getDp(), is(primeExponentP)); - assertThat(actual.getDq(), is(primeExponentQ)); - assertThat(actual.getQi(), is(crtCoefficient)); - } - - @Test(expected = InvalidPemException.class) - public void closedFileReaderShouldThrowInvalidPemException() throws InvalidPemException, IOException, InvalidKeyException { - PemToRSAKeyPair pemToRSAKeyPair = appFactory.pemToRSAKeyPair(); - - FileReader pemFileReader = makeFileReader("/certs/rsa-private-key.pem"); - pemFileReader.close(); - - pemToRSAKeyPair.translate(pemFileReader, Optional.of("test-key-id"), Use.SIGNATURE); - } - - @Test(expected = InvalidPemException.class) - public void emptyPemFileShouldThrowInvalidPemException() throws InvalidPemException, InvalidKeyException { - PemToRSAKeyPair pemToRSAKeyPair = appFactory.pemToRSAKeyPair(); - - FileReader pemFileReader = makeFileReader("/certs/rsa-private-key-bad.pem"); - pemToRSAKeyPair.translate(pemFileReader, Optional.of("test-key-id"), Use.SIGNATURE); - } - - @Test(expected = InvalidPemException.class) - public void csrFileShouldThrowInvalidPemException() throws InvalidPemException, InvalidKeyException { - PemToRSAKeyPair pemToRSAKeyPair = appFactory.pemToRSAKeyPair(); - - FileReader pemFileReader = makeFileReader("/certs/rsa-cert.csr"); - pemToRSAKeyPair.translate(pemFileReader, Optional.of("test-key-id"), Use.SIGNATURE); - } - - - -} \ No newline at end of file diff --git a/src/test/resources/certs/rsa-cert-bad.csr b/src/test/resources/certs/rsa-cert-bad.csr deleted file mode 100644 index e69de29..0000000 diff --git a/src/test/resources/certs/rsa-cert.csr b/src/test/resources/certs/rsa-cert.csr deleted file mode 100644 index e8ad5a5..0000000 --- a/src/test/resources/certs/rsa-cert.csr +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIICnTCCAYUCAQAwWDELMAkGA1UEBhMCVVMxETAPBgNVBAgTCElsbGlub2lzMRAw -DgYDVQQHEwdDaGljYWdvMRYwFAYDVQQKEw1Sb290IFNlcnZpY2VzMQwwCgYDVQQL -EwNKV1QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD55zuXRnN5CXDU -WXGjqEhh5eG3BN3sPp8mR/dw2CuNOHLd08vHMyhpYAXvpvAxf9EedYtoSA5bR0Xl -gwQJqe4vb8rGXCq9EdC63qIuvZmZNbRDNLXcjUmYOJZ2BczSamaKGscUpkd4/YKQ -vHtihv82tcVKAnacylWLZqC0nHKwTM/00vOlus7fnYSTE3qvVfRHyDQif/iAlaDr -KI4CL2caSaIpmC5MOhJ4eUh07p2gKCTIfXa4PvAYqVHB5Q2KmprZkOxSBmZVlQGy -H33OTKl2MBU/3oVfIgsjOcjxxvoKSaWx59U6YWgHbmq+i8Ub2DtcDaEDaqyEeVLv -xa4uRjVtAgMBAAGgADANBgkqhkiG9w0BAQUFAAOCAQEApxMtAwnS+hwNMdTghgMd -oNArpWTC7VKCCKYGffUzYX0LjANxj3pBNpBCzPFm7v2xbSyZ09iXMGz/Si/9Gr3B -Bhv5arQV35jOgv3WNDDEB+rwqmyfPvYjEYTaPiGQ7JWAGQZxxqsbUt2ZEt4aXyVK -S/4thpKARsPy454PdhYbVKc+sJ3tiA2dRP78I7FQhyOqv2biJHsJIynWjWVHTYxL -SK7KGMefKqOP0LjO+s1921yI6h39VhJ5NjqDCeRAdWkOvv1FGsgayNO4FD9grCYB -Z/shg+IpHO3TSNm+8hnGqmJAALZc8HfvrqbDeKzU6jSqMfs0lZC/3fiIj3beUzh3 -0A== ------END CERTIFICATE REQUEST----- diff --git a/src/test/resources/certs/rsa-private-key-bad.pem b/src/test/resources/certs/rsa-private-key-bad.pem deleted file mode 100644 index e69de29..0000000 diff --git a/src/test/resources/certs/rsa-private-key.pem b/src/test/resources/certs/rsa-private-key.pem deleted file mode 100644 index 4973d89..0000000 --- a/src/test/resources/certs/rsa-private-key.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEA+ec7l0ZzeQlw1Flxo6hIYeXhtwTd7D6fJkf3cNgrjThy3dPL -xzMoaWAF76bwMX/RHnWLaEgOW0dF5YMECanuL2/KxlwqvRHQut6iLr2ZmTW0QzS1 -3I1JmDiWdgXM0mpmihrHFKZHeP2CkLx7Yob/NrXFSgJ2nMpVi2agtJxysEzP9NLz -pbrO352EkxN6r1X0R8g0In/4gJWg6yiOAi9nGkmiKZguTDoSeHlIdO6doCgkyH12 -uD7wGKlRweUNipqa2ZDsUgZmVZUBsh99zkypdjAVP96FXyILIznI8cb6CkmlsefV -OmFoB25qvovFG9g7XA2hA2qshHlS78WuLkY1bQIDAQABAoIBAQCOAYkKUF1jxSqZ -cG4z+nePMetObfSRv4/+V9zTAfPVnuMfDLB6dKadIpSc9zb8Wc6CSXc7fd6yndCp -OAb+WtLfn94RU+RxZgM/fS2Z8+Gpfyv9GKHTP3I3jshpLqiSVSYJimfgYxCwPxaH -mqNefKnf8/C1OqseM5fizCG8ID7H0O7RMQCxz3Ebga+so8gTVANxIeGfFIXME1KN -bxpSAmladw8QNfjqYEPeMYtN9IiFd3spLSX2pChYyjg7SuH/KtUwjA9o+Gn2Zb7z -Rex3a/9jJOPSUbLrlqMYtnlGVjU/nU8rIqOImNDggxSbVk6781kJYI8P/ik2pXfs -tVL6S6jBAoGBAP1VQO6MlOceOe9mxB69ZmngcahoCZLfw4L7P2YS3tLITZFqlhO8 -IzyittX/D/pR9LbpB3nh6T0kmQjFZMT8Rh8B/z9pvfmffmxbL7uD/jk/zwGy0vb6 -gdbvGvn3ynGE6Xhsci7v0dZbqKNDvrCu7HNo8AFrYE/lQBQt7OPBEuXRAoGBAPyI -vFhFEOfE/9Ssl5Z2wd7S81jDg8ZgryaWJMi032TjtrHeCbEjefq5skvb0jvSdZvw -WvwsAaKdKCNjW675N53k2uRoszOBhg1Vo2HSsW8nH6J/Uh4fYPNBGEVyYj74CFcs -TTDNuxfFAD/3gWpkSVocD5cbgASrKotXQTDFfNDdAoGBAMqu9P5mt5OaGVwy6mJ1 -woSfMBA+/LnoEXKwNe8i1efqnjTkBCLR+Zc/z+yy30O1YocdNgAMASIML+xWkeMQ -u8F/RYqkvXwEYY+r/SqX1kRTivme6y7zCgK+1uR7nhro7iqNCWYINei8+NV3FBAk -Q8Wqhat9D1ec4YHDpK4sAUShAoGAAdKW0WhGM/YHBqjsOyjGQ25wVS6sD8141iV1 -RIGRry+5jNUWatHfuoCGmeePP+FH+gUlEvbaWCscNA0uhzfDP/972PQsfu2rYwNA -N5+Gqk+0+b5DgHYng/nvS+kEboHpxX9LW1PQyt4gH1YQ+AybPuw+7I9FQENf/jt1 -+/0g5n0CgYBK+8qOpRZnKbjHMfmvi73lywWoOFHWY3QciMjhnQ8F/EtHzaNgC6wr -WhzFxxdrL0+8bEyLwoUOudfcZXyBG3otSmGQLqn7ru+xRNSff8z8Y9E0GSKj3e7a -qPtzeBCa5irkAonpgowxfciO5SvLhM2wi8a3nTOqHmNkTVvDv9A/vA== ------END RSA PRIVATE KEY----- diff --git a/src/test/resources/log4j2.properties b/src/test/resources/log4j2.properties new file mode 100644 index 0000000..4a420b3 --- /dev/null +++ b/src/test/resources/log4j2.properties @@ -0,0 +1,7 @@ +appender.console.type = Console +appender.console.name = STDOUT +appender.console.layout.type = PatternLayout +appender.console.layout.pattern = %d{ISO8601} %5p %t %c{2}:%L - %m%n + +rootLogger.level=INFO +rootLogger.appenderRef.stdout.ref = STDOUT \ No newline at end of file