153 |
157 |
Auth0 is an easy to implement, adaptable authentication and authorization platform. To learn more checkout Why Auth0?
160 |161 | This project is licensed under the MIT license. See the LICENSE file for more info.
162 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | 6 | dependencies { 7 | // https://github.com/melix/japicmp-gradle-plugin/issues/36 8 | classpath 'com.google.guava:guava:31.1-jre' 9 | } 10 | } 11 | 12 | plugins { 13 | id 'java' 14 | id 'java-library' 15 | id 'jacoco' 16 | id 'me.champeau.gradle.japicmp' version '0.4.1' 17 | } 18 | 19 | repositories { 20 | mavenCentral() 21 | } 22 | 23 | apply from: rootProject.file('gradle/versioning.gradle') 24 | 25 | version = getVersionFromFile() 26 | group = GROUP 27 | logger.lifecycle("Using version ${version} for ${name} group $group") 28 | 29 | import me.champeau.gradle.japicmp.JapicmpTask 30 | 31 | project.afterEvaluate { 32 | def versions = project.ext.testInJavaVersions 33 | for (pluginJavaTestVersion in versions) { 34 | def taskName = "testInJava-${pluginJavaTestVersion}" 35 | tasks.register(taskName, Test) { 36 | def versionToUse = taskName.split("-").getAt(1) as Integer 37 | description = "Runs unit tests on Java version ${versionToUse}." 38 | project.logger.quiet("Test will be running in ${versionToUse}") 39 | group = 'verification' 40 | javaLauncher.set(javaToolchains.launcherFor { 41 | languageVersion = JavaLanguageVersion.of(versionToUse) 42 | }) 43 | shouldRunAfter(tasks.named('test')) 44 | } 45 | tasks.named('check') { 46 | dependsOn(taskName) 47 | } 48 | } 49 | 50 | project.configure(project) { 51 | def baselineVersion = project.ext.baselineCompareVersion 52 | task('apiDiff', type: JapicmpTask, dependsOn: 'jar') { 53 | oldClasspath.from(files(getBaselineJar(project, baselineVersion))) 54 | newClasspath.from(files(jar.archiveFile)) 55 | onlyModified = true 56 | failOnModification = true 57 | ignoreMissingClasses = true 58 | htmlOutputFile = file("$buildDir/reports/apiDiff/apiDiff.html") 59 | txtOutputFile = file("$buildDir/reports/apiDiff/apiDiff.txt") 60 | doLast { 61 | project.logger.quiet("Comparing against baseline version ${baselineVersion}") 62 | } 63 | } 64 | } 65 | } 66 | 67 | private static File getBaselineJar(Project project, String baselineVersion) { 68 | // Use detached configuration: https://github.com/square/okhttp/blob/master/build.gradle#L270 69 | def group = project.group 70 | try { 71 | def baseline = "${project.group}:${project.name}:$baselineVersion" 72 | project.group = 'virtual_group_for_japicmp' 73 | def dependency = project.dependencies.create(baseline + "@jar") 74 | return project.configurations.detachedConfiguration(dependency).files.find { 75 | it.name == "${project.name}-${baselineVersion}.jar" 76 | } 77 | } finally { 78 | project.group = group 79 | } 80 | } 81 | 82 | ext { 83 | baselineCompareVersion = '1.5.0' 84 | testInJavaVersions = [8, 11, 17, 21] 85 | } 86 | 87 | jacocoTestReport { 88 | reports { 89 | xml.enabled = true 90 | html.enabled = true 91 | } 92 | } 93 | 94 | java { 95 | toolchain { 96 | languageVersion = JavaLanguageVersion.of(8) 97 | } 98 | // Needed because of broken gradle metadata, see https://github.com/google/guava/issues/6612#issuecomment-1614992368 99 | sourceSets.all { 100 | configurations.getByName(runtimeClasspathConfigurationName) { 101 | attributes.attribute(Attribute.of("org.gradle.jvm.environment", String), "standard-jvm") 102 | } 103 | configurations.getByName(compileClasspathConfigurationName) { 104 | attributes.attribute(Attribute.of("org.gradle.jvm.environment", String), "standard-jvm") 105 | } 106 | } 107 | } 108 | 109 | compileJava { 110 | sourceCompatibility '1.8' 111 | targetCompatibility '1.8' 112 | } 113 | 114 | test { 115 | useJUnitPlatform() 116 | testLogging { 117 | events "skipped", "failed" 118 | exceptionFormat "short" 119 | } 120 | } 121 | 122 | dependencies { 123 | implementation 'javax.servlet:javax.servlet-api:3.1.0' 124 | implementation 'org.apache.commons:commons-lang3:3.12.0' 125 | implementation 'com.google.guava:guava-annotations:r03' 126 | implementation 'commons-codec:commons-codec:1.15' 127 | 128 | api 'com.auth0:auth0:1.45.1' 129 | api 'com.auth0:java-jwt:3.19.4' 130 | api 'com.auth0:jwks-rsa:0.22.1' 131 | 132 | testImplementation 'org.bouncycastle:bcprov-jdk15on:1.64' 133 | testImplementation 'org.hamcrest:java-hamcrest:2.0.0.0' 134 | testImplementation 'org.hamcrest:hamcrest-core:1.3' 135 | testImplementation 'org.mockito:mockito-core:2.8.9' 136 | testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1' 137 | testImplementation 'org.springframework:spring-test:4.3.14.RELEASE' 138 | testImplementation 'com.squareup.okhttp3:okhttp:4.11.0' 139 | } 140 | 141 | apply from: rootProject.file('gradle/maven-publish.gradle') 142 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | GROUP=com.auth0 2 | POM_ARTIFACT_ID=mvc-auth-commons 3 | 4 | POM_NAME=auth0-java-mvc-common 5 | POM_DESCRIPTION=Java library that simplifies the use of Auth0 for server-side MVC web apps 6 | POM_PACKAGING=jar 7 | 8 | POM_URL=https://github.com/auth0/auth0-java-mvc-common 9 | POM_SCM_URL=https://github.com/auth0/auth0-java-mvc-common 10 | 11 | POM_SCM_CONNECTION=scm:git:https://github.com/auth0/auth0-java-mvc-common.git 12 | POM_SCM_DEV_CONNECTION=scm:git:https://github.com/auth0/auth0-java-mvc-common.git 13 | 14 | POM_LICENCE_NAME=The MIT License (MIT) 15 | POM_LICENCE_URL=https://raw.githubusercontent.com/auth0/java-jwt/master/LICENSE 16 | POM_LICENCE_DIST=repo 17 | 18 | POM_DEVELOPER_ID=auth0 19 | POM_DEVELOPER_NAME=Auth0 20 | POM_DEVELOPER_EMAIL=oss@auth0.com -------------------------------------------------------------------------------- /gradle/maven-publish.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'maven-publish' 2 | apply plugin: 'signing' 3 | 4 | task('sourcesJar', type: Jar, dependsOn: classes) { 5 | archiveClassifier = 'sources' 6 | from sourceSets.main.allSource 7 | } 8 | 9 | task('javadocJar', type: Jar, dependsOn: javadoc) { 10 | archiveClassifier = 'javadoc' 11 | from javadoc.getDestinationDir() 12 | } 13 | tasks.withType(Javadoc).configureEach { 14 | javadocTool = javaToolchains.javadocToolFor { 15 | // Use latest JDK for javadoc generation 16 | languageVersion = JavaLanguageVersion.of(17) 17 | } 18 | } 19 | 20 | javadoc { 21 | // Specify the Java version that the project will use 22 | options.addStringOption('-release', "8") 23 | } 24 | artifacts { 25 | archives sourcesJar, javadocJar 26 | } 27 | 28 | 29 | final releaseRepositoryUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" 30 | final snapshotRepositoryUrl = "https://oss.sonatype.org/content/repositories/snapshots/" 31 | 32 | publishing { 33 | publications { 34 | mavenJava(MavenPublication) { 35 | 36 | groupId = GROUP 37 | artifactId = POM_ARTIFACT_ID 38 | version = getVersionName() 39 | 40 | artifact("$buildDir/libs/${project.name}-${version}.jar") 41 | artifact sourcesJar 42 | artifact javadocJar 43 | 44 | pom { 45 | name = POM_NAME 46 | packaging = POM_PACKAGING 47 | description = POM_DESCRIPTION 48 | url = POM_URL 49 | 50 | licenses { 51 | license { 52 | name = POM_LICENCE_NAME 53 | url = POM_LICENCE_URL 54 | distribution = POM_LICENCE_DIST 55 | } 56 | } 57 | 58 | developers { 59 | developer { 60 | id = POM_DEVELOPER_ID 61 | name = POM_DEVELOPER_NAME 62 | email = POM_DEVELOPER_EMAIL 63 | } 64 | } 65 | 66 | scm { 67 | url = POM_SCM_URL 68 | connection = POM_SCM_CONNECTION 69 | developerConnection = POM_SCM_DEV_CONNECTION 70 | } 71 | 72 | pom.withXml { 73 | def dependenciesNode = asNode().appendNode('dependencies') 74 | 75 | project.configurations.implementation.allDependencies.each { 76 | def dependencyNode = dependenciesNode.appendNode('dependency') 77 | dependencyNode.appendNode('groupId', it.group) 78 | dependencyNode.appendNode('artifactId', it.name) 79 | dependencyNode.appendNode('version', it.version) 80 | } 81 | } 82 | } 83 | } 84 | } 85 | repositories { 86 | maven { 87 | name = "sonatype" 88 | url = version.endsWith('SNAPSHOT') ? snapshotRepositoryUrl : releaseRepositoryUrl 89 | credentials { 90 | username = System.getenv("MAVEN_USERNAME") 91 | password = System.getenv("MAVEN_PASSWORD") 92 | } 93 | } 94 | } 95 | } 96 | 97 | signing { 98 | def signingKey = System.getenv("SIGNING_KEY") 99 | def signingPassword = System.getenv("SIGNING_PASSWORD") 100 | useInMemoryPgpKeys(signingKey, signingPassword) 101 | 102 | sign publishing.publications.mavenJava 103 | } 104 | 105 | javadoc { 106 | if(JavaVersion.current().isJava9Compatible()) { 107 | options.addBooleanOption('html5', true) 108 | } 109 | } 110 | 111 | tasks.named('publish').configure { 112 | dependsOn tasks.named('assemble') 113 | } -------------------------------------------------------------------------------- /gradle/versioning.gradle: -------------------------------------------------------------------------------- 1 | def getVersionFromFile() { 2 | def versionFile = rootProject.file('.version') 3 | return versionFile.text.readLines().first().trim() 4 | } 5 | 6 | def isSnapshot() { 7 | return hasProperty('isSnapshot') ? isSnapshot.toBoolean() : true 8 | } 9 | 10 | def getVersionName() { 11 | return isSnapshot() ? project.version+"-SNAPSHOT" : project.version 12 | } 13 | 14 | ext { 15 | getVersionName = this.&getVersionName 16 | getVersionFromFile = this.&getVersionFromFile 17 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/auth0/auth0-java-mvc-common/1fe03a1ae2071d2cbb454a84660270e53a0967a7/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /opslevel.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 1 3 | repository: 4 | owner: dx_sdks 5 | tier: 6 | tags: 7 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | } 5 | } 6 | 7 | rootProject.name = 'mvc-auth-commons' 8 | -------------------------------------------------------------------------------- /src/main/java/com/auth0/AlgorithmNameVerifier.java: -------------------------------------------------------------------------------- 1 | package com.auth0; 2 | 3 | @SuppressWarnings("unused") 4 | class AlgorithmNameVerifier extends SignatureVerifier { 5 | 6 | AlgorithmNameVerifier() { 7 | //Must only allow supported algorithms and never "none" algorithm 8 | super(null, "HS256", "RS256"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/auth0/AsymmetricSignatureVerifier.java: -------------------------------------------------------------------------------- 1 | package com.auth0; 2 | 3 | import com.auth0.jwk.Jwk; 4 | import com.auth0.jwk.JwkException; 5 | import com.auth0.jwk.JwkProvider; 6 | import com.auth0.jwt.JWT; 7 | import com.auth0.jwt.JWTVerifier; 8 | import com.auth0.jwt.algorithms.Algorithm; 9 | import com.auth0.jwt.interfaces.RSAKeyProvider; 10 | 11 | import java.security.interfaces.RSAPrivateKey; 12 | import java.security.interfaces.RSAPublicKey; 13 | 14 | @SuppressWarnings("unused") 15 | class AsymmetricSignatureVerifier extends SignatureVerifier { 16 | 17 | AsymmetricSignatureVerifier(JwkProvider jwkProvider) { 18 | super(createJWTVerifier(jwkProvider), "RS256"); 19 | } 20 | 21 | private static JWTVerifier createJWTVerifier(final JwkProvider jwkProvider) { 22 | Algorithm alg = Algorithm.RSA256(new RSAKeyProvider() { 23 | @Override 24 | public RSAPublicKey getPublicKeyById(String keyId) { 25 | try { 26 | Jwk jwk = jwkProvider.get(keyId); 27 | return (RSAPublicKey) jwk.getPublicKey(); 28 | } catch (JwkException ignored) { 29 | // JwkException handled by Algorithm verify implementation from java-jwt 30 | } 31 | return null; 32 | } 33 | 34 | @Override 35 | public RSAPrivateKey getPrivateKey() { 36 | //NO-OP 37 | return null; 38 | } 39 | 40 | @Override 41 | public String getPrivateKeyId() { 42 | //NO-OP 43 | return null; 44 | } 45 | }); 46 | return JWT.require(alg) 47 | .ignoreIssuedAt() 48 | .build(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/auth0/AuthCookie.java: -------------------------------------------------------------------------------- 1 | package com.auth0; 2 | 3 | import org.apache.commons.lang3.Validate; 4 | 5 | import java.io.UnsupportedEncodingException; 6 | import java.net.URLEncoder; 7 | import java.nio.charset.StandardCharsets; 8 | 9 | /** 10 | * Represents a cookie to be used for transfer of authentiction-based data such as state and nonce. 11 | * 12 | * This is an internal replacement for the Java Servlet Cookie implementation, so that it can set the SameSite 13 | * attribute (not yet supported in Java Servlet API). It is intended to be used via the Set-Cookie header. 14 | * 15 | * By default, cookies will have the HttpOnly attribute set, and a Max-Age of 600 seconds (10 minutes). 16 | */ 17 | class AuthCookie { 18 | 19 | private final static int MAX_AGE_SECONDS = 600; // 10 minutes 20 | 21 | private final String key; 22 | private final String value; 23 | private boolean secure; 24 | private SameSite sameSite; 25 | private String cookiePath; 26 | 27 | /** 28 | * Create a new instance. 29 | * 30 | * @param key The cookie key 31 | * @param value The cookie value 32 | */ 33 | AuthCookie(String key, String value) { 34 | Validate.notNull(key, "Key must not be null"); 35 | Validate.notNull(value, "Value must not be null"); 36 | 37 | this.key = key; 38 | this.value = value; 39 | } 40 | 41 | void setPath(String path) { 42 | this.cookiePath = path; 43 | } 44 | 45 | /** 46 | * Sets whether the Secure attribute should be set on the cookie. False by default. 47 | * 48 | * @param secure whether the Cookie should have the Secure attribute or not. 49 | */ 50 | void setSecure(boolean secure) { 51 | this.secure = secure; 52 | } 53 | 54 | /** 55 | * Sets the value of the SameSite attribute. Unless set, no SameSite attribute will be set on the cookie. 56 | * 57 | * @param sameSite The value of the SameSite attribute. 58 | */ 59 | void setSameSite(SameSite sameSite) { 60 | this.sameSite = sameSite; 61 | } 62 | 63 | /** 64 | * Builds and returns a string representing this cookie instance, to be used as the value of a "Set-Cookie" header. 65 | * The cookie key and value will be URL-encoded using the UTF-8 character set. 66 | * 67 | * @throws AssertionError if the UTF-8 character set is not supported on the running JVM. 68 | * @return the value of this cookie as a string to be used as the value of a "Set-Cookie" header. 69 | */ 70 | String buildHeaderString() { 71 | String baseCookieString = String.format("%s=%s; HttpOnly; Max-Age=%d", encode(key), encode(value), MAX_AGE_SECONDS); 72 | if (cookiePath != null) { 73 | baseCookieString = baseCookieString.concat(String.format("; Path=%s", cookiePath)); 74 | } 75 | if (sameSite != null) { 76 | baseCookieString = baseCookieString.concat(String.format("; SameSite=%s", encode(sameSite.getValue()))); 77 | } 78 | if (secure) { 79 | baseCookieString = baseCookieString.concat("; Secure"); 80 | } 81 | return baseCookieString; 82 | } 83 | 84 | private static String encode(String valueToEncode) { 85 | try { 86 | return URLEncoder.encode(valueToEncode, StandardCharsets.UTF_8.name()); 87 | } catch (UnsupportedEncodingException e) { 88 | throw new AssertionError("UTF-8 character set not supported", e.getCause()); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/auth0/AuthenticationController.java: -------------------------------------------------------------------------------- 1 | package com.auth0; 2 | 3 | import com.auth0.client.HttpOptions; 4 | import com.auth0.client.auth.AuthAPI; 5 | import com.auth0.jwk.JwkProvider; 6 | import com.auth0.net.Telemetry; 7 | import com.google.common.annotations.VisibleForTesting; 8 | import org.apache.commons.lang3.Validate; 9 | 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | 13 | 14 | /** 15 | * Base Auth0 Authenticator class. 16 | * Allows to easily authenticate using the Auth0 Hosted Login Page. 17 | */ 18 | @SuppressWarnings({"WeakerAccess", "UnusedReturnValue", "SameParameterValue"}) 19 | public class AuthenticationController { 20 | 21 | private final RequestProcessor requestProcessor; 22 | 23 | /** 24 | * Called from the Builder but also from tests in order to pass the mock. 25 | */ 26 | @VisibleForTesting 27 | AuthenticationController(RequestProcessor requestProcessor) { 28 | this.requestProcessor = requestProcessor; 29 | } 30 | 31 | @VisibleForTesting 32 | RequestProcessor getRequestProcessor() { 33 | return requestProcessor; 34 | } 35 | 36 | /** 37 | * Create a new {@link Builder} instance to configure the {@link AuthenticationController} response type and algorithm used on the verification. 38 | * By default it will request response type 'code' and later perform the Code Exchange, but if the response type is changed to 'token' it will handle 39 | * the Implicit Grant using the HS256 algorithm with the Client Secret as secret. 40 | * 41 | * @param domain the Auth0 domain 42 | * @param clientId the Auth0 application's client id 43 | * @param clientSecret the Auth0 application's client secret 44 | * @return a new Builder instance ready to configure 45 | */ 46 | public static Builder newBuilder(String domain, String clientId, String clientSecret) { 47 | return new Builder(domain, clientId, clientSecret); 48 | } 49 | 50 | 51 | public static class Builder { 52 | private static final String RESPONSE_TYPE_CODE = "code"; 53 | 54 | private final String domain; 55 | private final String clientId; 56 | private final String clientSecret; 57 | private String responseType; 58 | private JwkProvider jwkProvider; 59 | private Integer clockSkew; 60 | private Integer authenticationMaxAge; 61 | private boolean useLegacySameSiteCookie; 62 | private String organization; 63 | private String invitation; 64 | private HttpOptions httpOptions; 65 | private String cookiePath; 66 | 67 | Builder(String domain, String clientId, String clientSecret) { 68 | Validate.notNull(domain); 69 | Validate.notNull(clientId); 70 | Validate.notNull(clientSecret); 71 | 72 | this.domain = domain; 73 | this.clientId = clientId; 74 | this.clientSecret = clientSecret; 75 | this.responseType = RESPONSE_TYPE_CODE; 76 | this.useLegacySameSiteCookie = true; 77 | } 78 | 79 | /** 80 | * Customize certain aspects of the underlying HTTP client networking library, such as timeouts and proxy configuration. 81 | * 82 | * @param httpOptions a non-null {@code HttpOptions} 83 | * @return this same builder instance. 84 | */ 85 | public Builder withHttpOptions(HttpOptions httpOptions) { 86 | Validate.notNull(httpOptions); 87 | this.httpOptions = httpOptions; 88 | return this; 89 | } 90 | 91 | /** 92 | * Specify that transient authentication-based cookies such as state and nonce are created with the specified 93 | * {@code Path} cookie attribute. 94 | * 95 | * @param cookiePath the path to set on the cookie. 96 | * @return this builder instance. 97 | */ 98 | public Builder withCookiePath(String cookiePath) { 99 | Validate.notNull(cookiePath); 100 | this.cookiePath = cookiePath; 101 | return this; 102 | } 103 | 104 | /** 105 | * Change the response type to request in the Authorization step. Default value is 'code'. 106 | * 107 | * @param responseType the response type to request. Any combination of 'code', 'token' and 'id_token' but 'token id_token' is allowed, using a space as separator. 108 | * @return this same builder instance. 109 | */ 110 | public Builder withResponseType(String responseType) { 111 | Validate.notNull(responseType); 112 | this.responseType = responseType.trim().toLowerCase(); 113 | return this; 114 | } 115 | 116 | /** 117 | * Sets the Jwk Provider that will return the Public Key required to verify the token in case of Implicit Grant flows. 118 | * This is required if the Auth0 Application is signing the tokens with the RS256 algorithm. 119 | * 120 | * @param jwkProvider a valid Jwk provider. 121 | * @return this same builder instance. 122 | */ 123 | public Builder withJwkProvider(JwkProvider jwkProvider) { 124 | Validate.notNull(jwkProvider); 125 | this.jwkProvider = jwkProvider; 126 | return this; 127 | } 128 | 129 | /** 130 | * Sets the clock-skew or leeway value to use in the ID Token verification. The value must be in seconds. 131 | * Defaults to 60 seconds. 132 | * 133 | * @param clockSkew the clock-skew to use for ID Token verification, in seconds. 134 | * @return this same builder instance. 135 | */ 136 | public Builder withClockSkew(Integer clockSkew) { 137 | Validate.notNull(clockSkew); 138 | this.clockSkew = clockSkew; 139 | return this; 140 | } 141 | 142 | /** 143 | * Sets the allowable elapsed time in seconds since the last time user was authenticated. 144 | * By default there is no limit. 145 | * 146 | * @param maxAge the max age of the authentication, in seconds. 147 | * @return this same builder instance. 148 | */ 149 | public Builder withAuthenticationMaxAge(Integer maxAge) { 150 | Validate.notNull(maxAge); 151 | this.authenticationMaxAge = maxAge; 152 | return this; 153 | } 154 | 155 | /** 156 | * Sets whether fallback cookies will be set for clients that do not support SameSite=None cookie attribute. 157 | * The SameSite Cookie attribute will only be set to "None" if the reponseType includes "id_token". 158 | * By default this is true. 159 | * @param useLegacySameSiteCookie whether fallback auth-based cookies should be set. 160 | * @return this same builder instance. 161 | */ 162 | public Builder withLegacySameSiteCookie(boolean useLegacySameSiteCookie) { 163 | this.useLegacySameSiteCookie = useLegacySameSiteCookie; 164 | return this; 165 | } 166 | 167 | /** 168 | * Sets the organization query string parameter value used to login to an organization. 169 | * 170 | * @param organization The ID or name of the organization to log the user in to. 171 | * @return the builder instance. 172 | */ 173 | public Builder withOrganization(String organization) { 174 | Validate.notNull(organization); 175 | this.organization = organization; 176 | return this; 177 | } 178 | 179 | /** 180 | * Sets the invitation query string parameter to join an organization. If using this, you must also specify the 181 | * organization using {@linkplain Builder#withOrganization(String)}. 182 | * 183 | * @param invitation The ID of the invitation to accept. This is available on the URL that is provided when accepting an invitation. 184 | * @return the builder instance. 185 | */ 186 | public Builder withInvitation(String invitation) { 187 | Validate.notNull(invitation); 188 | this.invitation = invitation; 189 | return this; 190 | } 191 | 192 | /** 193 | * Create a new {@link AuthenticationController} instance that will handle both Code Grant and Implicit Grant flows using either Code Exchange or Token Signature verification. 194 | * 195 | * @return a new instance of {@link AuthenticationController}. 196 | * @throws UnsupportedOperationException if the Implicit Grant is chosen and the environment doesn't support UTF-8 encoding. 197 | */ 198 | public AuthenticationController build() throws UnsupportedOperationException { 199 | AuthAPI apiClient = createAPIClient(domain, clientId, clientSecret, httpOptions); 200 | setupTelemetry(apiClient); 201 | 202 | final boolean expectedAlgorithmIsExplicitlySetAndAsymmetric = jwkProvider != null; 203 | final SignatureVerifier signatureVerifier; 204 | if (expectedAlgorithmIsExplicitlySetAndAsymmetric) { 205 | signatureVerifier = new AsymmetricSignatureVerifier(jwkProvider); 206 | } else if (responseType.contains(RESPONSE_TYPE_CODE)) { 207 | // Old behavior: To maintain backwards-compatibility when 208 | // no explicit algorithm is set by the user, we 209 | // must skip ID Token signature check. 210 | signatureVerifier = new AlgorithmNameVerifier(); 211 | } else { 212 | signatureVerifier = new SymmetricSignatureVerifier(clientSecret); 213 | } 214 | 215 | String issuer = getIssuer(domain); 216 | IdTokenVerifier.Options verifyOptions = createIdTokenVerificationOptions(issuer, clientId, signatureVerifier); 217 | verifyOptions.setClockSkew(clockSkew); 218 | verifyOptions.setMaxAge(authenticationMaxAge); 219 | verifyOptions.setOrganization(this.organization); 220 | 221 | RequestProcessor processor = new RequestProcessor.Builder(apiClient, responseType, verifyOptions) 222 | .withLegacySameSiteCookie(useLegacySameSiteCookie) 223 | .withOrganization(organization) 224 | .withInvitation(invitation) 225 | .withCookiePath(cookiePath) 226 | .build(); 227 | 228 | return new AuthenticationController(processor); 229 | } 230 | 231 | @VisibleForTesting 232 | IdTokenVerifier.Options createIdTokenVerificationOptions(String issuer, String audience, SignatureVerifier signatureVerifier) { 233 | return new IdTokenVerifier.Options(issuer, audience, signatureVerifier); 234 | } 235 | 236 | @VisibleForTesting 237 | AuthAPI createAPIClient(String domain, String clientId, String clientSecret, HttpOptions httpOptions) { 238 | if (httpOptions != null) { 239 | return new AuthAPI(domain, clientId, clientSecret, httpOptions); 240 | } 241 | return new AuthAPI(domain, clientId, clientSecret); 242 | } 243 | 244 | @VisibleForTesting 245 | void setupTelemetry(AuthAPI client) { 246 | Telemetry telemetry = new Telemetry("auth0-java-mvc-common", obtainPackageVersion()); 247 | client.setTelemetry(telemetry); 248 | } 249 | 250 | @VisibleForTesting 251 | String obtainPackageVersion() { 252 | //Value if taken from jar's manifest file. 253 | //Call will return null on dev environment (outside of a jar) 254 | return getClass().getPackage().getImplementationVersion(); 255 | } 256 | 257 | private String getIssuer(String domain) { 258 | if (!domain.startsWith("http://") && !domain.startsWith("https://")) { 259 | domain = "https://" + domain; 260 | } 261 | if (!domain.endsWith("/")) { 262 | domain = domain + "/"; 263 | } 264 | return domain; 265 | } 266 | } 267 | 268 | /** 269 | * Whether to enable or not the HTTP Logger for every Request and Response. 270 | * Enabling this can expose sensitive information. 271 | * 272 | * @param enabled whether to enable the HTTP logger or not. 273 | */ 274 | public void setLoggingEnabled(boolean enabled) { 275 | requestProcessor.getClient().setLoggingEnabled(enabled); 276 | } 277 | 278 | /** 279 | * Disable sending the Telemetry header on every request to the Auth0 API 280 | */ 281 | public void doNotSendTelemetry() { 282 | requestProcessor.getClient().doNotSendTelemetry(); 283 | } 284 | 285 | /** 286 | * Process a request to obtain a set of {@link Tokens} that represent successful authentication or authorization. 287 | * 288 | * This method should be called when processing the callback request to your application. It will validate 289 | * authentication-related request parameters, handle performing a Code Exchange request if using 290 | * the "code" response type, and verify the integrity of the ID token (if present). 291 | * 292 | *Important: When using this API, you must also use {@link AuthenticationController#buildAuthorizeUrl(HttpServletRequest, HttpServletResponse, String)} 293 | * when building the {@link AuthorizeUrl} that the user will be redirected to to login. Failure to do so may result 294 | * in a broken login experience for the user.
295 | * 296 | * @param request the received request to process. 297 | * @param response the received response to process. 298 | * @return the Tokens obtained after the user authentication. 299 | * @throws InvalidRequestException if the error is result of making an invalid authentication request. 300 | * @throws IdentityVerificationException if an error occurred while verifying the request tokens. 301 | */ 302 | public Tokens handle(HttpServletRequest request, HttpServletResponse response) throws IdentityVerificationException { 303 | Validate.notNull(request, "request must not be null"); 304 | Validate.notNull(response, "response must not be null"); 305 | 306 | return requestProcessor.process(request, response); 307 | } 308 | 309 | /** 310 | * Process a request to obtain a set of {@link Tokens} that represent successful authentication or authorization. 311 | * 312 | * This method should be called when processing the callback request to your application. It will validate 313 | * authentication-related request parameters, handle performing a Code Exchange request if using 314 | * the "code" response type, and verify the integrity of the ID token (if present). 315 | * 316 | *Important: When using this API, you must also use the {@link AuthenticationController#buildAuthorizeUrl(HttpServletRequest, String)} 317 | * when building the {@link AuthorizeUrl} that the user will be redirected to to login. Failure to do so may result 318 | * in a broken login experience for the user.
319 | * 320 | * @deprecated This method uses the {@link javax.servlet.http.HttpSession} for auth-based data, and is incompatible 321 | * with clients that are using the "id_token" or "token" responseType with browsers that enforce SameSite cookie 322 | * restrictions. This method will be removed in version 2.0.0. Use 323 | * {@link AuthenticationController#handle(HttpServletRequest, HttpServletResponse)} instead. 324 | * 325 | * @param request the received request to process. 326 | * @return the Tokens obtained after the user authentication. 327 | * @throws InvalidRequestException if the error is result of making an invalid authentication request. 328 | * @throws IdentityVerificationException if an error occurred while verifying the request tokens. 329 | */ 330 | @Deprecated 331 | public Tokens handle(HttpServletRequest request) throws IdentityVerificationException { 332 | Validate.notNull(request, "request must not be null"); 333 | 334 | return requestProcessor.process(request, null); 335 | } 336 | 337 | /** 338 | * Pre builds an Auth0 Authorize Url with the given redirect URI using a random state and a random nonce if applicable. 339 | * 340 | *Important: When using this API, you must also obtain the tokens using the 341 | * {@link AuthenticationController#handle(HttpServletRequest)} method. Failure to do so may result in a broken login 342 | * experience for users.
343 | * 344 | * @deprecated This method stores data in the {@link javax.servlet.http.HttpSession}, and is incompatible with clients 345 | * that are using the "id_token" or "token" responseType with browsers that enforce SameSite cookie restrictions. 346 | * This method will be removed in version 2.0.0. Use 347 | * {@link AuthenticationController#buildAuthorizeUrl(HttpServletRequest, HttpServletResponse, String)} instead. 348 | * 349 | * @param request the caller request. Used to keep the session context. 350 | * @param redirectUri the url to call back with the authentication result. 351 | * @return the authorize url builder to continue any further parameter customization. 352 | */ 353 | @Deprecated 354 | public AuthorizeUrl buildAuthorizeUrl(HttpServletRequest request, String redirectUri) { 355 | Validate.notNull(request, "request must not be null"); 356 | Validate.notNull(redirectUri, "redirectUri must not be null"); 357 | 358 | String state = StorageUtils.secureRandomString(); 359 | String nonce = StorageUtils.secureRandomString(); 360 | 361 | return requestProcessor.buildAuthorizeUrl(request, null, redirectUri, state, nonce); 362 | } 363 | 364 | /** 365 | * Pre builds an Auth0 Authorize Url with the given redirect URI using a random state and a random nonce if applicable. 366 | * 367 | *Important: When using this API, you must also obtain the tokens using the 368 | * {@link AuthenticationController#handle(HttpServletRequest, HttpServletResponse)} method. Failure to do so will result in a broken login 369 | * experience for users.
370 | * 371 | * @param request the HTTP request 372 | * @param response the HTTP response. Used to store auth-based cookies. 373 | * @param redirectUri the url to call back with the authentication result. 374 | * @return the authorize url builder to continue any further parameter customization. 375 | */ 376 | public AuthorizeUrl buildAuthorizeUrl(HttpServletRequest request, HttpServletResponse response, String redirectUri) { 377 | Validate.notNull(request, "request must not be null"); 378 | Validate.notNull(response, "response must not be null"); 379 | Validate.notNull(redirectUri, "redirectUri must not be null"); 380 | 381 | String state = StorageUtils.secureRandomString(); 382 | String nonce = StorageUtils.secureRandomString(); 383 | 384 | return requestProcessor.buildAuthorizeUrl(request, response, redirectUri, state, nonce); 385 | } 386 | 387 | } 388 | -------------------------------------------------------------------------------- /src/main/java/com/auth0/AuthorizeUrl.java: -------------------------------------------------------------------------------- 1 | package com.auth0; 2 | 3 | import com.auth0.client.auth.AuthAPI; 4 | import com.auth0.client.auth.AuthorizeUrlBuilder; 5 | import com.auth0.exception.Auth0Exception; 6 | import com.auth0.json.auth.PushedAuthorizationResponse; 7 | 8 | import javax.servlet.http.HttpServletRequest; 9 | import javax.servlet.http.HttpServletResponse; 10 | import java.util.*; 11 | 12 | import static com.auth0.IdentityVerificationException.API_ERROR; 13 | 14 | /** 15 | * Class to create and customize an Auth0 Authorize URL. 16 | * It's not reusable. 17 | */ 18 | @SuppressWarnings({"UnusedReturnValue", "WeakerAccess", "unused", "SameParameterValue"}) 19 | public class AuthorizeUrl { 20 | 21 | private static final String SCOPE_OPENID = "openid"; 22 | 23 | private HttpServletResponse response; 24 | private HttpServletRequest request; 25 | private final String responseType; 26 | private boolean useLegacySameSiteCookie = true; 27 | private boolean setSecureCookie = false; 28 | private String nonce; 29 | private String state; 30 | private final AuthAPI authAPI; 31 | private String cookiePath; 32 | 33 | private boolean used; 34 | private Map
159 | * 1). Responsible for validating the request.
160 | * 2). Exchanging the authorization code received with this HTTP request for Auth0 tokens.
161 | * 3). Validating the ID Token.
162 | * 4). Clearing the stored state, nonce and max_age values.
163 | * 5). Handling success and any failure outcomes.
164 | *
165 | * @throws IdentityVerificationException if an error occurred while processing the request
166 | */
167 | Tokens process(HttpServletRequest request, HttpServletResponse response) throws IdentityVerificationException {
168 | assertNoError(request);
169 | assertValidState(request, response);
170 |
171 | Tokens frontChannelTokens = getFrontChannelTokens(request);
172 | List
8 | *
14 | */
15 | @SuppressWarnings({"unused", "WeakerAccess"})
16 | public class Tokens implements Serializable {
17 |
18 | private static final long serialVersionUID = 2371882820082543721L;
19 |
20 | private final String accessToken;
21 | private final String idToken;
22 | private final String refreshToken;
23 | private final String type;
24 | private final Long expiresIn;
25 |
26 | /**
27 | * @param accessToken access token for Auth0 API
28 | * @param idToken identity token with user information
29 | * @param refreshToken refresh token that can be used to request new tokens without signing in again
30 | * @param type token type
31 | * @param expiresIn token expiration
32 | */
33 | public Tokens(String accessToken, String idToken, String refreshToken, String type, Long expiresIn) {
34 | this.accessToken = accessToken;
35 | this.idToken = idToken;
36 | this.refreshToken = refreshToken;
37 | this.type = type;
38 | this.expiresIn = expiresIn;
39 | }
40 |
41 | /**
42 | * Getter for the Access Token.
43 | *
44 | * @return the Access Token.
45 | */
46 | public String getAccessToken() {
47 | return accessToken;
48 | }
49 |
50 | /**
51 | * Getter for the Id Token.
52 | *
53 | * @return the Id Token.
54 | */
55 | public String getIdToken() {
56 | return idToken;
57 | }
58 |
59 | /**
60 | * Getter for the Refresh Token.
61 | *
62 | * @return the Refresh Token.
63 | */
64 | public String getRefreshToken() {
65 | return refreshToken;
66 | }
67 |
68 | /**
69 | * Getter for the token Type .
70 | *
71 | * @return the Type of the token.
72 | */
73 | public String getType() {
74 | return type;
75 | }
76 |
77 | /**
78 | * Getter for the Expiration time of the Token.
79 | *
80 | * @return the expiration time.
81 | */
82 | public Long getExpiresIn() {
83 | return expiresIn;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/main/java/com/auth0/TransientCookieStore.java:
--------------------------------------------------------------------------------
1 | package com.auth0;
2 |
3 | import org.apache.commons.lang3.Validate;
4 |
5 | import javax.servlet.http.Cookie;
6 | import javax.servlet.http.HttpServletRequest;
7 | import javax.servlet.http.HttpServletResponse;
8 | import java.io.UnsupportedEncodingException;
9 | import java.net.URLDecoder;
10 | import java.nio.charset.StandardCharsets;
11 |
12 | /**
13 | * Allows storage and retrieval/removal of cookies.
14 | */
15 | class TransientCookieStore {
16 |
17 | // Prevent instantiation
18 | private TransientCookieStore() {}
19 |
20 |
21 | /**
22 | * Stores a state value as a cookie on the response.
23 | *
24 | * @param response the response object to set the cookie on
25 | * @param state the value for the state cookie. If null, no cookie will be set.
26 | * @param sameSite the value for the SameSite attribute on the cookie
27 | * @param useLegacySameSiteCookie whether to set a fallback cookie or not
28 | * @param isSecureCookie whether to always set the Secure cookie attribute or not
29 | */
30 | static void storeState(HttpServletResponse response, String state, SameSite sameSite, boolean useLegacySameSiteCookie, boolean isSecureCookie, String cookiePath) {
31 | store(response, StorageUtils.STATE_KEY, state, sameSite, useLegacySameSiteCookie, isSecureCookie, cookiePath);
32 | }
33 |
34 | /**
35 | * Stores a nonce value as a cookie on the response.
36 | *
37 | * @param response the response object to set the cookie on
38 | * @param nonce the value for the nonce cookie. If null, no cookie will be set.
39 | * @param sameSite the value for the SameSite attribute on the cookie
40 | * @param useLegacySameSiteCookie whether to set a fallback cookie or not
41 | * @param isSecureCookie whether to always set the Secure cookie attribute or not
42 | */
43 | static void storeNonce(HttpServletResponse response, String nonce, SameSite sameSite, boolean useLegacySameSiteCookie, boolean isSecureCookie, String cookiePath) {
44 | store(response, StorageUtils.NONCE_KEY, nonce, sameSite, useLegacySameSiteCookie, isSecureCookie, cookiePath);
45 | }
46 |
47 | /**
48 | * Gets the value associated with the state cookie and removes it.
49 | *
50 | * @param request the request object
51 | * @param response the response object
52 | * @return the value of the state cookie, if it exists
53 | */
54 | static String getState(HttpServletRequest request, HttpServletResponse response) {
55 | return getOnce(StorageUtils.STATE_KEY, request, response);
56 | }
57 |
58 | /**
59 | * Gets the value associated with the nonce cookie and removes it.
60 | *
61 | * @param request the request object
62 | * @param response the response object
63 | * @return the value of the nonce cookie, if it exists
64 | */
65 | static String getNonce(HttpServletRequest request, HttpServletResponse response) {
66 | return getOnce(StorageUtils.NONCE_KEY, request, response);
67 | }
68 |
69 | private static void store(HttpServletResponse response, String key, String value, SameSite sameSite, boolean useLegacySameSiteCookie, boolean isSecureCookie, String cookiePath) {
70 | Validate.notNull(response, "response must not be null");
71 | Validate.notNull(key, "key must not be null");
72 | Validate.notNull(sameSite, "sameSite must not be null");
73 |
74 | if (value == null) {
75 | return;
76 | }
77 |
78 | boolean isSameSiteNone = SameSite.NONE == sameSite;
79 |
80 | AuthCookie sameSiteCookie = new AuthCookie(key, value);
81 | sameSiteCookie.setSameSite(sameSite);
82 | sameSiteCookie.setSecure(isSameSiteNone || isSecureCookie);
83 | if (cookiePath != null) {
84 | sameSiteCookie.setPath(cookiePath);
85 | }
86 |
87 | // Servlet Cookie API does not yet support setting the SameSite attribute, so just set cookie on header
88 | response.addHeader("Set-Cookie", sameSiteCookie.buildHeaderString());
89 |
90 | // set legacy fallback cookie (if configured) for clients that won't accept SameSite=None
91 | if (isSameSiteNone && useLegacySameSiteCookie) {
92 | AuthCookie legacyCookie = new AuthCookie("_" + key, value);
93 | legacyCookie.setSecure(isSecureCookie);
94 | response.addHeader("Set-Cookie", legacyCookie.buildHeaderString());
95 | }
96 |
97 | }
98 |
99 | private static String getOnce(String cookieName, HttpServletRequest request, HttpServletResponse response) {
100 | Cookie[] requestCookies = request.getCookies();
101 | if (requestCookies == null) {
102 | return null;
103 | }
104 |
105 | Cookie foundCookie = null;
106 | for (Cookie c : requestCookies) {
107 | if (cookieName.equals(c.getName())) {
108 | foundCookie = c;
109 | break;
110 | }
111 | }
112 |
113 | String foundCookieVal = null;
114 | if (foundCookie != null) {
115 | foundCookieVal = decode(foundCookie.getValue());
116 | delete(foundCookie, response);
117 | }
118 |
119 | Cookie foundLegacyCookie = null;
120 | for (Cookie c : requestCookies) {
121 | if (("_" + cookieName).equals(c.getName())) {
122 | foundLegacyCookie = c;
123 | break;
124 | }
125 | }
126 |
127 | String foundLegacyCookieVal = null;
128 | if (foundLegacyCookie != null) {
129 | foundLegacyCookieVal = decode(foundLegacyCookie.getValue());
130 | delete(foundLegacyCookie, response);
131 | }
132 |
133 | return foundCookieVal != null ? foundCookieVal : foundLegacyCookieVal;
134 | }
135 |
136 | private static void delete(Cookie cookie, HttpServletResponse response) {
137 | cookie.setMaxAge(0);
138 | cookie.setValue("");
139 | response.addCookie(cookie);
140 | }
141 |
142 | private static String decode(String valueToDecode) {
143 | try {
144 | return URLDecoder.decode(valueToDecode, StandardCharsets.UTF_8.name());
145 | } catch (UnsupportedEncodingException e) {
146 | throw new AssertionError("UTF-8 character set not supported", e.getCause());
147 | }
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/src/test/java/com/auth0/AuthorizeUrlTest.java:
--------------------------------------------------------------------------------
1 | package com.auth0;
2 |
3 | import com.auth0.client.HttpOptions;
4 | import com.auth0.client.auth.AuthAPI;
5 | import com.auth0.exception.Auth0Exception;
6 | import com.auth0.json.auth.PushedAuthorizationResponse;
7 | import com.auth0.net.Request;
8 | import okhttp3.HttpUrl;
9 | import org.junit.jupiter.api.BeforeEach;
10 | import org.junit.jupiter.api.Test;
11 | import org.springframework.mock.web.MockHttpServletRequest;
12 | import org.springframework.mock.web.MockHttpServletResponse;
13 |
14 | import javax.servlet.http.HttpServletRequest;
15 | import javax.servlet.http.HttpServletResponse;
16 | import java.util.Collection;
17 | import java.util.Map;
18 |
19 | import static org.hamcrest.CoreMatchers.*;
20 | import static org.hamcrest.MatcherAssert.assertThat;
21 | import static org.junit.jupiter.api.Assertions.assertEquals;
22 | import static org.junit.jupiter.api.Assertions.assertThrows;
23 | import static org.mockito.ArgumentMatchers.*;
24 | import static org.mockito.Mockito.mock;
25 | import static org.mockito.Mockito.when;
26 |
27 | public class AuthorizeUrlTest {
28 |
29 | private AuthAPI client;
30 | private HttpServletResponse response;
31 | private HttpServletRequest request;
32 |
33 | @BeforeEach
34 | public void setUp() {
35 | client = new AuthAPI("domain.auth0.com", "clientId", "clientSecret");
36 | request = new MockHttpServletRequest();
37 | response = new MockHttpServletResponse();
38 | }
39 |
40 | @Test
41 | public void shouldBuildValidStringUrl() {
42 | String url = new AuthorizeUrl(client, request, response, "https://redirect.to/me", "id_token token")
43 | .build();
44 | assertThat(url, is(notNullValue()));
45 | assertThat(HttpUrl.parse(url), is(notNullValue()));
46 | }
47 |
48 | @Test
49 | public void shouldSetDefaultScope() {
50 | String url = new AuthorizeUrl(client, request, response, "https://redirect.to/me", "id_token token")
51 | .build();
52 | assertThat(HttpUrl.parse(url).queryParameter("scope"), is("openid"));
53 | }
54 |
55 | @Test
56 | public void shouldSetResponseType() {
57 | String url = new AuthorizeUrl(client, request, response, "https://redirect.to/me", "id_token token")
58 | .build();
59 | assertThat(HttpUrl.parse(url).queryParameter("response_type"), is("id_token token"));
60 | }
61 |
62 | @Test
63 | public void shouldSetRedirectUrl() {
64 | String url = new AuthorizeUrl(client, request, response, "https://redirect.to/me", "id_token token")
65 | .build();
66 | assertThat(HttpUrl.parse(url).queryParameter("redirect_uri"), is("https://redirect.to/me"));
67 | }
68 |
69 | @Test
70 | public void shouldSetConnection() {
71 | String url = new AuthorizeUrl(client, request, response, "https://redirect.to/me", "id_token token")
72 | .withConnection("facebook")
73 | .build();
74 | assertThat(HttpUrl.parse(url).queryParameter("connection"), is("facebook"));
75 | }
76 |
77 | @Test
78 | public void shouldSetAudience() {
79 | String url = new AuthorizeUrl(client, request, response, "https://redirect.to/me", "id_token token")
80 | .withAudience("https://api.auth0.com/")
81 | .build();
82 | assertThat(HttpUrl.parse(url).queryParameter("audience"), is("https://api.auth0.com/"));
83 | }
84 |
85 | @Test
86 | public void shouldSetNonceSameSiteAndLegacyCookieByDefault() {
87 | String url = new AuthorizeUrl(client, request, response, "https://redirect.to/me", "id_token token")
88 | .withNonce("asdfghjkl")
89 | .build();
90 | assertThat(HttpUrl.parse(url).queryParameter("nonce"), is("asdfghjkl"));
91 |
92 | Collection