diff --git a/build.gradle b/build.gradle index 455c9e7..ba0a402 100644 --- a/build.gradle +++ b/build.gradle @@ -10,11 +10,11 @@ plugins { id 'com.github.ben-manes.versions' version '0.51.0' id 'com.google.cloud.tools.jib' version '3.4.3' apply false id 'org.sonarqube' version '5.1.0.4882' - id 'pl.allegro.tech.build.axion-release' version '1.18.0' + id 'pl.allegro.tech.build.axion-release' version '1.18.13' } wrapper { - gradleVersion = '8.8' + gradleVersion = '8.10.2' distributionType = Wrapper.DistributionType.ALL } @@ -42,17 +42,17 @@ allprojects { } ext { - assertj_version = '3.26.0' + assertj_version = '3.26.3' jjwt_version = '0.12.6' jsr305_version = '3.0.2' junit4_version = '4.13.2' - junit5_version = '5.10.3' - keycloak_version = '25.0.1' - mockito_version = '5.12.0' + junit5_version = '5.11.2' + keycloak_version = '26.0.0' + mockito_version = '5.14.2' picocli_version = '4.7.6' - restassured_version = '5.4.0' - slf4j_version = '2.0.13' - vertx_version = '4.5.8' + restassured_version = '5.5.0' + slf4j_version = '2.0.16' + vertx_version = '4.5.10' license_name = 'The Apache License, Version 2.0' license_url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' diff --git a/example-backend/build.gradle b/example-backend/build.gradle index d86a595..3a3d5e3 100644 --- a/example-backend/build.gradle +++ b/example-backend/build.gradle @@ -1,6 +1,6 @@ buildscript { ext { - springBootVersion = '3.3.1' + springBootVersion = '3.3.4' } repositories { mavenCentral() diff --git a/example-frontend-react/build.gradle b/example-frontend-react/build.gradle index 2c1943b..c5edd82 100644 --- a/example-frontend-react/build.gradle +++ b/example-frontend-react/build.gradle @@ -1,7 +1,7 @@ import static groovy.io.FileType.FILES plugins { - id 'com.github.node-gradle.node' version '7.0.2' + id 'com.github.node-gradle.node' version '7.1.0' } def nodeDir = 'bin/nodejs' diff --git a/example-frontend-react/package.json b/example-frontend-react/package.json index f77e8a6..77c51ae 100644 --- a/example-frontend-react/package.json +++ b/example-frontend-react/package.json @@ -4,8 +4,8 @@ "private": true, "license": "Apache-2.0", "dependencies": { - "axios": "^1.7.4", - "keycloak-js": "^25.0.1", + "axios": "^1.7.7", + "keycloak-js": "^26.0.1", "react": "^18.3.1", "react-dom": "^18.3.1", "react-scripts": "5.0.1" @@ -29,7 +29,7 @@ "not op_mini all" ], "devDependencies": { - "cypress": "^13.13.0", - "cypress-keycloak": "^2.0.1" + "cypress": "^13.15.0", + "cypress-keycloak": "^2.0.2" } } diff --git a/example-frontend-react/yarn.lock b/example-frontend-react/yarn.lock index 7f7f3a4..aa050ad 100644 --- a/example-frontend-react/yarn.lock +++ b/example-frontend-react/yarn.lock @@ -2258,10 +2258,10 @@ resolved "https://registry.yarnpkg.com/@csstools/normalize.css/-/normalize.css-12.0.0.tgz#a9583a75c3f150667771f30b60d9f059473e62c4" integrity sha512-M0qqxAcwCsIVfpFQSlGN5XjXWu8l5JDZN+fPt1LeW5SZexQTgnaEvgXAY+CeygRw0EeppWHi12JxESWiWrB0Sg== -"@cypress/request@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@cypress/request/-/request-3.0.1.tgz#72d7d5425236a2413bd3d8bb66d02d9dc3168960" - integrity sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ== +"@cypress/request@^3.0.4": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@cypress/request/-/request-3.0.5.tgz#d893a6e68ce2636c085fcd8d7283c3186499ba63" + integrity sha512-v+XHd9XmWbufxF1/bTaVm2yhbxY+TB4YtWRqF2zaXBlDNMkls34KiATz0AVDLavL3iB6bQk9/7n3oY1EoLSWGA== dependencies: aws-sign2 "~0.7.0" aws4 "^1.8.0" @@ -2269,14 +2269,14 @@ combined-stream "~1.0.6" extend "~3.0.2" forever-agent "~0.6.1" - form-data "~2.3.2" - http-signature "~1.3.6" + form-data "~4.0.0" + http-signature "~1.4.0" is-typedarray "~1.0.0" isstream "~0.1.2" json-stringify-safe "~5.0.1" mime-types "~2.1.19" performance-now "^2.1.0" - qs "6.10.4" + qs "6.13.0" safe-buffer "^5.1.2" tough-cookie "^4.1.3" tunnel-agent "^0.6.0" @@ -3710,10 +3710,10 @@ axe-core@^4.3.5: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.3.5.tgz#78d6911ba317a8262bfee292aeafcc1e04b49cc5" integrity sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA== -axios@^1.7.4: - version "1.7.4" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.4.tgz#4c8ded1b43683c8dd362973c393f3ede24052aa2" - integrity sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw== +axios@^1.7.7: + version "1.7.7" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" + integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== dependencies: follow-redirects "^1.15.6" form-data "^4.0.0" @@ -4330,7 +4330,7 @@ colorette@^2.0.16: resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== -combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: +combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -4726,20 +4726,20 @@ cssstyle@^2.3.0: dependencies: cssom "~0.3.6" -cypress-keycloak@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/cypress-keycloak/-/cypress-keycloak-2.0.1.tgz#0e8c762debfefd9d99a4ef06692250d076cc39fa" - integrity sha512-RzHi0YNle8Ft0hMUpCceCsRbNOON9jtAPNWD/9NE+3egCx/pSMJY7RNuL1oGDyzdjjE5WvOU6llC3uYBKrFtJQ== +cypress-keycloak@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/cypress-keycloak/-/cypress-keycloak-2.0.2.tgz#fd76cc276a325182a7313e9456bc5319724201ae" + integrity sha512-pHCjn68pai6y3MPuaM7c6UEidIfaXfl2+4WKhQ/8wgprQb7YlPcuBI1txBC477O2OFLx9ii1XlSXXq7fUP8ZAg== dependencies: base64-js "^1.5.1" js-sha256 "^0.9.0" -cypress@^13.13.0: - version "13.13.0" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-13.13.0.tgz#52b2914c0c1c7d8a51ec2e3df18e13995da95951" - integrity sha512-ou/MQUDq4tcDJI2FsPaod2FZpex4kpIK43JJlcBgWrX8WX7R/05ZxGTuxedOuZBfxjZxja+fbijZGyxiLP6CFA== +cypress@^13.15.0: + version "13.15.0" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-13.15.0.tgz#5eca5387ef34b2e611cfa291967c69c2cd39381d" + integrity sha512-53aO7PwOfi604qzOkCSzNlWquCynLlKE/rmmpSPcziRH6LNfaDUAklQT6WJIsD8ywxlIy+uVZsnTMCCQVd2kTw== dependencies: - "@cypress/request" "^3.0.0" + "@cypress/request" "^3.0.4" "@cypress/xvfb" "^1.2.4" "@types/sinonjs__fake-timers" "8.1.1" "@types/sizzle" "^2.3.2" @@ -5976,13 +5976,13 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== +form-data@~4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.1.tgz#ba1076daaaa5bfd7e99c1a6cb02aa0a5cff90d48" + integrity sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw== dependencies: asynckit "^0.4.0" - combined-stream "^1.0.6" + combined-stream "^1.0.8" mime-types "^2.1.12" forwarded@0.2.0: @@ -6486,14 +6486,14 @@ http-proxy@^1.18.1: follow-redirects "^1.0.0" requires-port "^1.0.0" -http-signature@~1.3.6: - version "1.3.6" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.3.6.tgz#cb6fbfdf86d1c974f343be94e87f7fc128662cf9" - integrity sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw== +http-signature@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.4.0.tgz#dee5a9ba2bf49416abc544abd6d967f6a94c8c3f" + integrity sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg== dependencies: assert-plus "^1.0.0" jsprim "^2.0.2" - sshpk "^1.14.1" + sshpk "^1.18.0" https-proxy-agent@^5.0.0: version "5.0.0" @@ -7426,11 +7426,6 @@ jest@^27.4.3: import-local "^3.0.2" jest-cli "^27.4.7" -js-sha256@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.11.0.tgz#256a921d9292f7fe98905face82e367abaca9576" - integrity sha512-6xNlKayMZvds9h1Y1VWc0fQHQ82BxTXizWPEtEeGvmOUYpBRy4gbWroHLpzowe6xiQhHpelCQiE7HEdznyBL9Q== - js-sha256@^0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.9.0.tgz#0b89ac166583e91ef9123644bd3c5334ce9d0966" @@ -7593,18 +7588,10 @@ jsx-ast-utils@^3.2.1: array-includes "^3.1.3" object.assign "^4.1.2" -jwt-decode@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-4.0.0.tgz#2270352425fd413785b2faf11f6e755c5151bd4b" - integrity sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA== - -keycloak-js@^25.0.1: - version "25.0.1" - resolved "https://registry.yarnpkg.com/keycloak-js/-/keycloak-js-25.0.1.tgz#6197e1184dd86ecc1b55f8b19df0f61c466a00c0" - integrity sha512-ns5sKQ5Iz3UyVGIKq2XBBXNZTlTCg9bzybR+JB2Vn+fDHIo9EGgAY4kzrBWMwbeFuegY+qJwGs05N+W9jgY9tg== - dependencies: - js-sha256 "^0.11.0" - jwt-decode "^4.0.0" +keycloak-js@^26.0.1: + version "26.0.1" + resolved "https://registry.yarnpkg.com/keycloak-js/-/keycloak-js-26.0.1.tgz#02042600c6cb8146389785bc5ce89b6c1bf92063" + integrity sha512-Fhn7a9FVKTpno2yfhL6/eiQrmEgBkiM+toVBJ1+g8kasG6CeiMKnI93byL5W8W3M7Ld3Im1QD3kuL/z4vJHGcg== kind-of@^6.0.2: version "6.0.3" @@ -9187,13 +9174,6 @@ q@^1.1.2: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= -qs@6.10.4: - version "6.10.4" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.4.tgz#6a3003755add91c0ec9eacdc5f878b034e73f9e7" - integrity sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g== - dependencies: - side-channel "^1.0.4" - qs@6.13.0: version "6.13.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" @@ -10055,10 +10035,10 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= -sshpk@^1.14.1: - version "1.17.0" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" - integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== +sshpk@^1.18.0: + version "1.18.0" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.18.0.tgz#1663e55cddf4d688b86a46b77f0d5fe363aba028" + integrity sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ== dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" diff --git a/example-integration-docker/build.gradle b/example-integration-docker/build.gradle index d1d48e3..5b9903d 100644 --- a/example-integration-docker/build.gradle +++ b/example-integration-docker/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'com.avast.gradle.docker-compose' version '0.17.7' + id 'com.avast.gradle.docker-compose' version '0.17.10' } composeUp { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 28f5fcf..18330fc 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/mock/build.gradle b/mock/build.gradle index 0c4e040..22dcfe5 100644 --- a/mock/build.gradle +++ b/mock/build.gradle @@ -27,7 +27,7 @@ dependencies { testImplementation "io.rest-assured:rest-assured:$restassured_version" // required to mock RoutingContext testImplementation "io.vertx:vertx-codegen:$vertx_version" - testImplementation 'net.javacrumbs.json-unit:json-unit-assertj:3.4.0' + testImplementation 'net.javacrumbs.json-unit:json-unit-assertj:3.4.1' testImplementation "org.assertj:assertj-core:$assertj_version" testImplementation "org.junit.jupiter:junit-jupiter-api" testImplementation "org.junit.jupiter:junit-jupiter-params" @@ -40,7 +40,7 @@ tasks.register('addResources', Copy) { // make sure to fail if both JARs contain a NOTICE, then we need to merge the files somehow ... duplicatesStrategy = DuplicatesStrategy.FAIL from files(tarTree(configurations.jsResourceJar.singleFile)) { - include '/package/dist/keycloak.js' + include '/package/lib/keycloak.js' include '/META-INF/NOTICE' } from files(zipTree(configurations.htmlResourceJar.singleFile)) { diff --git a/mock/src/main/java/com/tngtech/keycloakmock/impl/UrlConfiguration.java b/mock/src/main/java/com/tngtech/keycloakmock/impl/UrlConfiguration.java index aecc9fc..0cc3c2b 100644 --- a/mock/src/main/java/com/tngtech/keycloakmock/impl/UrlConfiguration.java +++ b/mock/src/main/java/com/tngtech/keycloakmock/impl/UrlConfiguration.java @@ -1,6 +1,7 @@ package com.tngtech.keycloakmock.impl; import com.tngtech.keycloakmock.api.ServerConfig; +import io.vertx.ext.web.RoutingContext; import java.net.URI; import java.net.URISyntaxException; import java.util.Objects; @@ -60,6 +61,13 @@ public UrlConfiguration forRequestContext( return new UrlConfiguration(this, requestHost, requestRealm); } + @Nonnull + public UrlConfiguration forRequestContext(RoutingContext routingContext) { + String requestHostname = routingContext.request().getHeader("Host"); + String requestRealm = routingContext.pathParam("realm"); + return new UrlConfiguration(this, requestHostname, requestRealm); + } + @Nonnull URI getBaseUrl() { try { diff --git a/mock/src/main/java/com/tngtech/keycloakmock/impl/dagger/ServerModule.java b/mock/src/main/java/com/tngtech/keycloakmock/impl/dagger/ServerModule.java index 79729ac..8ea3e51 100644 --- a/mock/src/main/java/com/tngtech/keycloakmock/impl/dagger/ServerModule.java +++ b/mock/src/main/java/com/tngtech/keycloakmock/impl/dagger/ServerModule.java @@ -4,7 +4,6 @@ import com.tngtech.keycloakmock.impl.UrlConfiguration; import com.tngtech.keycloakmock.impl.handler.AuthenticationRoute; import com.tngtech.keycloakmock.impl.handler.CommonHandler; -import com.tngtech.keycloakmock.impl.handler.DelegationRoute; import com.tngtech.keycloakmock.impl.handler.FailureHandler; import com.tngtech.keycloakmock.impl.handler.IFrameRoute; import com.tngtech.keycloakmock.impl.handler.JwksRoute; @@ -12,7 +11,6 @@ import com.tngtech.keycloakmock.impl.handler.LogoutRoute; import com.tngtech.keycloakmock.impl.handler.OptionalBasicAuthHandler; import com.tngtech.keycloakmock.impl.handler.OutOfBandLoginRoute; -import com.tngtech.keycloakmock.impl.handler.RequestUrlConfigurationHandler; import com.tngtech.keycloakmock.impl.handler.ResourceFileHandler; import com.tngtech.keycloakmock.impl.handler.TokenRoute; import com.tngtech.keycloakmock.impl.handler.WellKnownRoute; @@ -21,6 +19,7 @@ import dagger.Provides; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpMethod; import io.vertx.core.http.HttpServer; import io.vertx.core.http.HttpServerOptions; import io.vertx.core.net.JksOptions; @@ -79,7 +78,7 @@ ResourceFileHandler provideCookie2Handler() { @Singleton @Named("keycloakJs") ResourceFileHandler provideKeycloakJsHandler() { - return new ResourceFileHandler("/package/dist/keycloak.js"); + return new ResourceFileHandler("/package/lib/keycloak.js"); } @Provides @@ -123,7 +122,7 @@ HttpServerOptions provideHttpServerOptions( if (defaultConfiguration.getProtocol().isTls()) { options .setSsl(true) - .setKeyStoreOptions(new JksOptions().setValue(keyStoreBuffer.get()).setPassword("")); + .setKeyCertOptions(new JksOptions().setValue(keyStoreBuffer.get()).setPassword("")); } return options; } @@ -133,7 +132,6 @@ HttpServerOptions provideHttpServerOptions( Router provideRouter( @Nonnull UrlConfiguration defaultConfiguration, @Nonnull Vertx vertx, - @Nonnull RequestUrlConfigurationHandler requestUrlConfigurationHandler, @Nonnull CommonHandler commonHandler, @Nonnull FailureHandler failureHandler, @Nonnull JwksRoute jwksRoute, @@ -146,14 +144,12 @@ Router provideRouter( @Nonnull @Named("cookie1") ResourceFileHandler thirdPartyCookies1Route, @Nonnull @Named("cookie2") ResourceFileHandler thirdPartyCookies2Route, @Nonnull LogoutRoute logoutRoute, - @Nonnull DelegationRoute delegationRoute, @Nonnull OutOfBandLoginRoute outOfBandLoginRoute, @Nonnull @Named("keycloakJs") ResourceFileHandler keycloakJsRoute) { UrlConfiguration routing = defaultConfiguration.forRequestContext(null, ":realm"); Router router = Router.router(vertx); router .route() - .handler(requestUrlConfigurationHandler) .handler(commonHandler) .failureHandler(failureHandler) .failureHandler(ErrorHandler.create(vertx)); @@ -176,8 +172,11 @@ Router provideRouter( router .get(routing.getOpenIdPath("3p-cookies/step2.html").getPath()) .handler(thirdPartyCookies2Route); - router.get(routing.getEndSessionEndpoint().getPath()).handler(logoutRoute); - router.get(routing.getOpenIdPath("delegated").getPath()).handler(delegationRoute); + router + .route(routing.getEndSessionEndpoint().getPath()) + .method(HttpMethod.GET) + .method(HttpMethod.POST) + .handler(logoutRoute); router.get(routing.getOutOfBandLoginLoginEndpoint().getPath()).handler(outOfBandLoginRoute); router.route("/auth/js/keycloak.js").handler(keycloakJsRoute); return router; diff --git a/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/AuthenticationRoute.java b/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/AuthenticationRoute.java index f5bee15..6e0b2b0 100644 --- a/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/AuthenticationRoute.java +++ b/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/AuthenticationRoute.java @@ -1,7 +1,5 @@ package com.tngtech.keycloakmock.impl.handler; -import static com.tngtech.keycloakmock.impl.handler.RequestUrlConfigurationHandler.CTX_REQUEST_CONFIGURATION; - import com.tngtech.keycloakmock.impl.UrlConfiguration; import com.tngtech.keycloakmock.impl.helper.RedirectHelper; import com.tngtech.keycloakmock.impl.helper.UserInputSanitizer; @@ -30,12 +28,16 @@ public class AuthenticationRoute implements Handler { @Nonnull private final SessionRepository sessionRepository; @Nonnull private final RedirectHelper redirectHelper; + @Nonnull private final UrlConfiguration baseConfiguration; @Inject AuthenticationRoute( - @Nonnull SessionRepository sessionRepository, @Nonnull RedirectHelper redirectHelper) { + @Nonnull SessionRepository sessionRepository, + @Nonnull RedirectHelper redirectHelper, + @Nonnull UrlConfiguration baseConfiguration) { this.sessionRepository = sessionRepository; this.redirectHelper = redirectHelper; + this.baseConfiguration = baseConfiguration; } @Override @@ -59,7 +61,7 @@ public void handle(@Nonnull RoutingContext routingContext) { .map(s -> Arrays.asList(s.split(","))) .orElseGet(Collections::emptyList); - UrlConfiguration requestConfiguration = routingContext.get(CTX_REQUEST_CONFIGURATION); + UrlConfiguration requestConfiguration = baseConfiguration.forRequestContext(routingContext); PersistentSession session = request.toSession( diff --git a/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/DelegationRoute.java b/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/DelegationRoute.java deleted file mode 100644 index c398aec..0000000 --- a/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/DelegationRoute.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.tngtech.keycloakmock.impl.handler; - -import io.vertx.core.Handler; -import io.vertx.core.http.HttpHeaders; -import io.vertx.ext.web.RoutingContext; -import io.vertx.ext.web.common.template.TemplateEngine; -import javax.annotation.Nonnull; -import javax.inject.Inject; -import javax.inject.Singleton; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@Singleton -public class DelegationRoute implements Handler { - private static final Logger LOG = LoggerFactory.getLogger(DelegationRoute.class); - private static final String HEADER = "header"; - private static final String BODY = "body"; - - @Nonnull private final TemplateEngine engine; - - @Inject - DelegationRoute(@Nonnull TemplateEngine engine) { - this.engine = engine; - } - - @Override - public void handle(@Nonnull RoutingContext routingContext) { - if ("true".equals(routingContext.queryParams().get("error"))) { - routingContext.put(HEADER, "Delegation failed"); - routingContext.put( - BODY, "You need to check the output of your client to see what went wrong."); - } else { - routingContext.put(HEADER, "Delegation successful"); - routingContext.put(BODY, "You may now close this browser window."); - } - engine - .render(routingContext.data(), "delegation.ftl") - .onSuccess( - b -> routingContext.response().putHeader(HttpHeaders.CONTENT_TYPE, "text/html").end(b)) - .onFailure( - t -> { - LOG.error("Unable to render login page", t); - routingContext.fail(t); - }); - } -} diff --git a/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/LoginRoute.java b/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/LoginRoute.java index cc53b7d..a81dafa 100644 --- a/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/LoginRoute.java +++ b/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/LoginRoute.java @@ -1,6 +1,5 @@ package com.tngtech.keycloakmock.impl.handler; -import static com.tngtech.keycloakmock.impl.handler.RequestUrlConfigurationHandler.CTX_REQUEST_CONFIGURATION; import static com.tngtech.keycloakmock.impl.helper.RedirectHelper.KEYCLOAK_SESSION_COOKIE; import com.tngtech.keycloakmock.impl.UrlConfiguration; @@ -35,15 +34,18 @@ public class LoginRoute implements Handler { @Nonnull private final SessionRepository sessionRepository; @Nonnull private final RedirectHelper redirectHelper; @Nonnull private final TemplateEngine engine; + @Nonnull private final UrlConfiguration baseConfiguration; @Inject LoginRoute( @Nonnull SessionRepository sessionRepository, @Nonnull RedirectHelper redirectHelper, - @Nonnull TemplateEngine engine) { + @Nonnull TemplateEngine engine, + @Nonnull UrlConfiguration baseConfiguration) { this.sessionRepository = sessionRepository; this.redirectHelper = redirectHelper; this.engine = engine; + this.baseConfiguration = baseConfiguration; } @Override @@ -73,7 +75,7 @@ public void handle(@Nonnull RoutingContext routingContext) { .setResponseMode(routingContext.queryParams().get(RESPONSE_MODE)) .build(); - UrlConfiguration requestConfiguration = routingContext.get(CTX_REQUEST_CONFIGURATION); + UrlConfiguration requestConfiguration = baseConfiguration.forRequestContext(routingContext); if (existingSession.isPresent()) { PersistentSession oldSession = existingSession.get(); PersistentSession newSession = diff --git a/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/LogoutRoute.java b/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/LogoutRoute.java index 6fbe99d..7590ae8 100644 --- a/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/LogoutRoute.java +++ b/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/LogoutRoute.java @@ -1,6 +1,5 @@ package com.tngtech.keycloakmock.impl.handler; -import static com.tngtech.keycloakmock.impl.handler.RequestUrlConfigurationHandler.CTX_REQUEST_CONFIGURATION; import static com.tngtech.keycloakmock.impl.helper.RedirectHelper.KEYCLOAK_SESSION_COOKIE; import com.tngtech.keycloakmock.impl.UrlConfiguration; @@ -30,12 +29,16 @@ public class LogoutRoute implements Handler { @Nonnull private final SessionRepository sessionRepository; @Nonnull private final RedirectHelper redirectHelper; + @Nonnull private final UrlConfiguration baseConfiguration; @Inject LogoutRoute( - @Nonnull SessionRepository sessionRepository, @Nonnull RedirectHelper redirectHelper) { + @Nonnull SessionRepository sessionRepository, + @Nonnull RedirectHelper redirectHelper, + @Nonnull UrlConfiguration baseConfiguration) { this.sessionRepository = sessionRepository; this.redirectHelper = redirectHelper; + this.baseConfiguration = baseConfiguration; } @Override @@ -44,7 +47,7 @@ public void handle(@Nonnull RoutingContext routingContext) { if (redirectUri == null) { // for backwards compatibility: redirectUri = routingContext.queryParams().get(LEGACY_REDIRECT_URI); } - UrlConfiguration requestConfiguration = routingContext.get(CTX_REQUEST_CONFIGURATION); + UrlConfiguration requestConfiguration = baseConfiguration.forRequestContext(routingContext); invalidateSession(routingContext); routingContext .response() diff --git a/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/RequestUrlConfigurationHandler.java b/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/RequestUrlConfigurationHandler.java deleted file mode 100644 index 794bc47..0000000 --- a/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/RequestUrlConfigurationHandler.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.tngtech.keycloakmock.impl.handler; - -import com.tngtech.keycloakmock.impl.UrlConfiguration; -import io.vertx.core.Handler; -import io.vertx.ext.web.RoutingContext; -import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.annotation.Nonnull; -import javax.inject.Inject; -import javax.inject.Singleton; - -@Singleton -public class RequestUrlConfigurationHandler implements Handler { - public static final String CTX_REQUEST_CONFIGURATION = "requestConfiguration"; - - private static final Pattern REALM_PATTERN = Pattern.compile("/auth/realms/([^/]*)(?:$|/.*)"); - - @Nonnull private final UrlConfiguration baseConfiguration; - - @Inject - RequestUrlConfigurationHandler(@Nonnull UrlConfiguration baseConfiguration) { - this.baseConfiguration = Objects.requireNonNull(baseConfiguration); - } - - @Override - public void handle(@Nonnull RoutingContext routingContext) { - String requestHostname = routingContext.request().getHeader("Host"); - String requestRealm = null; - Matcher matcher = REALM_PATTERN.matcher(routingContext.normalizedPath()); - if (matcher.matches()) { - requestRealm = matcher.group(1); - } - routingContext.put( - CTX_REQUEST_CONFIGURATION, - baseConfiguration.forRequestContext(requestHostname, requestRealm)); - routingContext.next(); - } -} diff --git a/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/TokenRoute.java b/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/TokenRoute.java index 869315b..c6a3524 100644 --- a/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/TokenRoute.java +++ b/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/TokenRoute.java @@ -1,7 +1,5 @@ package com.tngtech.keycloakmock.impl.handler; -import static com.tngtech.keycloakmock.impl.handler.RequestUrlConfigurationHandler.CTX_REQUEST_CONFIGURATION; - import com.tngtech.keycloakmock.impl.UrlConfiguration; import com.tngtech.keycloakmock.impl.helper.TokenHelper; import com.tngtech.keycloakmock.impl.session.AdHocSession; @@ -27,11 +25,16 @@ public class TokenRoute implements Handler { @Nonnull private final SessionRepository sessionRepository; @Nonnull private final TokenHelper tokenHelper; + @Nonnull private final UrlConfiguration baseConfiguration; @Inject - TokenRoute(@Nonnull SessionRepository sessionRepository, @Nonnull TokenHelper tokenHelper) { + TokenRoute( + @Nonnull SessionRepository sessionRepository, + @Nonnull TokenHelper tokenHelper, + @Nonnull UrlConfiguration baseConfiguration) { this.sessionRepository = sessionRepository; this.tokenHelper = tokenHelper; + this.baseConfiguration = baseConfiguration; } @Override @@ -58,7 +61,7 @@ public void handle(@Nonnull RoutingContext routingContext) { private void handleAuthorizationCodeFlow(RoutingContext routingContext) { // here again we use the equality of authorization code and session ID String sessionId = routingContext.request().getFormAttribute(CODE); - UrlConfiguration requestConfiguration = routingContext.get(CTX_REQUEST_CONFIGURATION); + UrlConfiguration requestConfiguration = baseConfiguration.forRequestContext(routingContext); String token = Optional.ofNullable(sessionRepository.getSession(sessionId)) .map(s -> tokenHelper.getToken(s, requestConfiguration)) @@ -105,7 +108,7 @@ private void handlePasswordFlow(RoutingContext routingContext) { routingContext.fail(400); return; } - UrlConfiguration requestConfiguration = routingContext.get(CTX_REQUEST_CONFIGURATION); + UrlConfiguration requestConfiguration = baseConfiguration.forRequestContext(routingContext); String password = routingContext.request().getFormAttribute("password"); Session session = @@ -142,7 +145,8 @@ private void handleClientCredentialsFlow(RoutingContext routingContext) { return; } - final UrlConfiguration requestConfiguration = routingContext.get(CTX_REQUEST_CONFIGURATION); + final UrlConfiguration requestConfiguration = + baseConfiguration.forRequestContext(routingContext); final Session session = AdHocSession.fromClientIdUsernameAndPassword( diff --git a/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/WellKnownRoute.java b/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/WellKnownRoute.java index b349a67..09b13a3 100644 --- a/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/WellKnownRoute.java +++ b/mock/src/main/java/com/tngtech/keycloakmock/impl/handler/WellKnownRoute.java @@ -1,7 +1,5 @@ package com.tngtech.keycloakmock.impl.handler; -import static com.tngtech.keycloakmock.impl.handler.RequestUrlConfigurationHandler.CTX_REQUEST_CONFIGURATION; - import com.tngtech.keycloakmock.impl.UrlConfiguration; import io.vertx.core.Handler; import io.vertx.core.json.JsonArray; @@ -16,12 +14,16 @@ @Singleton public class WellKnownRoute implements Handler { + @Nonnull private final UrlConfiguration baseConfiguration; + @Inject - WellKnownRoute() {} + WellKnownRoute(@Nonnull UrlConfiguration baseConfiguration) { + this.baseConfiguration = baseConfiguration; + } @Override public void handle(@Nonnull RoutingContext routingContext) { - UrlConfiguration requestConfiguration = routingContext.get(CTX_REQUEST_CONFIGURATION); + UrlConfiguration requestConfiguration = baseConfiguration.forRequestContext(routingContext); routingContext .response() .putHeader("content-type", "application/json") diff --git a/mock/src/main/resources/delegation.ftl b/mock/src/main/resources/delegation.ftl deleted file mode 100644 index 255add6..0000000 --- a/mock/src/main/resources/delegation.ftl +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - Login result - - -

${header}

-

${body}

- - diff --git a/mock/src/test/java/com/tngtech/keycloakmock/api/KeycloakMockIntegrationTest.java b/mock/src/test/java/com/tngtech/keycloakmock/api/KeycloakMockIntegrationTest.java index 002f7d7..47baabc 100644 --- a/mock/src/test/java/com/tngtech/keycloakmock/api/KeycloakMockIntegrationTest.java +++ b/mock/src/test/java/com/tngtech/keycloakmock/api/KeycloakMockIntegrationTest.java @@ -27,6 +27,7 @@ import io.restassured.RestAssured; import io.restassured.http.ContentType; import io.restassured.http.Cookie; +import io.restassured.http.Method; import io.restassured.path.json.JsonPath; import io.restassured.response.ExtractableResponse; import io.restassured.response.Response; @@ -305,7 +306,23 @@ void mock_server_login_with_implicit_flow_works() throws Exception { openLoginPageAgainAndExpectToBeLoggedInAlready(secondRequest, keycloakSession); // logout - logoutAndExpectSessionCookieReset(); + logoutAndExpectSessionCookieReset(Method.GET); + } + + @Test + void mock_server_logout_with_POST_works() throws Exception { + keycloakMock = new KeycloakMock(); + keycloakMock.start(); + + // open login page to create session (implicit flow) + ClientRequest firstRequest = new ClientRequest("redirect-uri", "state", "nonce", "id_token"); + String callbackUrl = openLoginPageAndGetCallbackUrl(firstRequest); + + // simulate login + loginAndValidateAndReturnSessionCookie(firstRequest, callbackUrl); + + // logout + logoutAndExpectSessionCookieReset(Method.POST); } @Test @@ -326,7 +343,7 @@ void mock_server_login_with_authorization_code_flow_works() throws Exception { validateRefreshTokenFlow(refreshToken, firstRequest.getNonce()); // logout - logoutAndExpectSessionCookieReset(); + logoutAndExpectSessionCookieReset(Method.GET); } private String openLoginPageAndGetCallbackUrl(ClientRequest request) { @@ -494,11 +511,12 @@ private String validateCookieAndReturnSessionId(Cookie keycloakSession) { return components[2]; } - private void logoutAndExpectSessionCookieReset() { + private void logoutAndExpectSessionCookieReset(Method method) { RestAssured.given() .config(config().redirect(redirectConfig().followRedirects(false))) .when() - .get( + .request( + method, "http://localhost:8000/auth/realms/realm/protocol/openid-connect/logout?post_logout_redirect_uri=redirect_uri") .then() .assertThat() diff --git a/mock/src/test/java/com/tngtech/keycloakmock/impl/UrlConfigurationTest.java b/mock/src/test/java/com/tngtech/keycloakmock/impl/UrlConfigurationTest.java index cc78641..be002aa 100644 --- a/mock/src/test/java/com/tngtech/keycloakmock/impl/UrlConfigurationTest.java +++ b/mock/src/test/java/com/tngtech/keycloakmock/impl/UrlConfigurationTest.java @@ -2,8 +2,12 @@ import static com.tngtech.keycloakmock.api.ServerConfig.aServerConfig; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import com.tngtech.keycloakmock.api.ServerConfig; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.ext.web.RoutingContext; import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -118,6 +122,22 @@ void context_parameters_are_used_correctly( assertThat(urlConfiguration.getIssuer()).hasToString(expected); } + @ParameterizedTest + @MethodSource("request_host_and_realm_and_expected") + void context_parameters_are_extracted_correctly( + String requestHost, String requestRealm, String expected) { + RoutingContext routingContext = mock(); + HttpServerRequest httpServerRequest = mock(); + when(routingContext.request()).thenReturn(httpServerRequest); + when(httpServerRequest.getHeader("Host")).thenReturn(requestHost); + when(routingContext.pathParam("realm")).thenReturn(requestRealm); + + urlConfiguration = + new UrlConfiguration(aServerConfig().build()).forRequestContext(routingContext); + + assertThat(urlConfiguration.getIssuer()).hasToString(expected); + } + @ParameterizedTest @MethodSource("request_host_and_realm_and_expected_with_no_context_path") void context_parameters_are_used_correctly_for_server_config_with_no_context_path( diff --git a/mock/src/test/java/com/tngtech/keycloakmock/impl/handler/AuthenticationRouteTest.java b/mock/src/test/java/com/tngtech/keycloakmock/impl/handler/AuthenticationRouteTest.java index 5003fd8..bf738eb 100644 --- a/mock/src/test/java/com/tngtech/keycloakmock/impl/handler/AuthenticationRouteTest.java +++ b/mock/src/test/java/com/tngtech/keycloakmock/impl/handler/AuthenticationRouteTest.java @@ -1,6 +1,5 @@ package com.tngtech.keycloakmock.impl.handler; -import static com.tngtech.keycloakmock.impl.handler.RequestUrlConfigurationHandler.CTX_REQUEST_CONFIGURATION; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; @@ -46,7 +45,8 @@ class AuthenticationRouteTest { @Mock private RoutingContext routingContext; @Mock private HttpServerRequest request; @Mock private HttpServerResponse response; - @Mock private UrlConfiguration urlConfiguration; + @Mock private UrlConfiguration baseConfiguration; + @Mock private UrlConfiguration contextConfiguration; @Mock private SessionRequest sessionRequest; @Mock private PersistentSession session; @Mock private Cookie cookie; @@ -62,13 +62,14 @@ void setup() { @Test void missing_session_causes_error() { - uut = new AuthenticationRoute(sessionRepository, redirectHelper); + uut = new AuthenticationRoute(sessionRepository, redirectHelper, baseConfiguration); uut.handle(routingContext); verify(sessionRepository).getRequest(SESSION_ID); verify(routingContext).fail(404); - verifyNoMoreInteractions(urlConfiguration, sessionRepository, redirectHelper); + verifyNoMoreInteractions( + baseConfiguration, contextConfiguration, sessionRepository, redirectHelper); } @Test @@ -76,19 +77,20 @@ void missing_username_causes_error() { doReturn(sessionRequest).when(sessionRepository).getRequest(SESSION_ID); doReturn(request).when(routingContext).request(); - uut = new AuthenticationRoute(sessionRepository, redirectHelper); + uut = new AuthenticationRoute(sessionRepository, redirectHelper, baseConfiguration); uut.handle(routingContext); verify(sessionRepository).getRequest(SESSION_ID); verify(routingContext).fail(400); - verifyNoMoreInteractions(urlConfiguration, sessionRepository, redirectHelper); + verifyNoMoreInteractions( + baseConfiguration, contextConfiguration, sessionRepository, redirectHelper); } @Test void correct_token_is_created() { setupValidRequest(); - uut = new AuthenticationRoute(sessionRepository, redirectHelper); + uut = new AuthenticationRoute(sessionRepository, redirectHelper, baseConfiguration); uut.handle(routingContext); @@ -108,13 +110,13 @@ private void setupValidRequest() { doReturn(request).when(routingContext).request(); doReturn(sessionRequest).when(sessionRepository).getRequest(SESSION_ID); doReturn(session).when(sessionRequest).toSession(eq(USER), anyList()); - doReturn(urlConfiguration).when(routingContext).get(CTX_REQUEST_CONFIGURATION); - doReturn(HOSTNAME).when(urlConfiguration).getHostname(); + doReturn(contextConfiguration).when(baseConfiguration).forRequestContext(routingContext); + doReturn(HOSTNAME).when(contextConfiguration).getHostname(); doReturn(response).when(routingContext).response(); doReturn(response).when(response).addCookie(any(Cookie.class)); doReturn(response).when(response).putHeader(eq("location"), anyString()); doReturn(response).when(response).setStatusCode(anyInt()); - doReturn(cookie).when(redirectHelper).getSessionCookie(session, urlConfiguration); - doReturn(REDIRECT_URI).when(redirectHelper).getRedirectLocation(session, urlConfiguration); + doReturn(cookie).when(redirectHelper).getSessionCookie(session, contextConfiguration); + doReturn(REDIRECT_URI).when(redirectHelper).getRedirectLocation(session, contextConfiguration); } } diff --git a/mock/src/test/java/com/tngtech/keycloakmock/impl/handler/RequestUrlConfigurationHandlerTest.java b/mock/src/test/java/com/tngtech/keycloakmock/impl/handler/RequestUrlConfigurationHandlerTest.java deleted file mode 100644 index 67d24d7..0000000 --- a/mock/src/test/java/com/tngtech/keycloakmock/impl/handler/RequestUrlConfigurationHandlerTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.tngtech.keycloakmock.impl.handler; - -import static com.tngtech.keycloakmock.impl.handler.RequestUrlConfigurationHandler.CTX_REQUEST_CONFIGURATION; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.verify; - -import com.tngtech.keycloakmock.impl.UrlConfiguration; -import io.vertx.core.http.HttpServerRequest; -import io.vertx.ext.web.RoutingContext; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@ExtendWith(MockitoExtension.class) -class RequestUrlConfigurationHandlerTest { - private static final String REQUEST_HOST = "requestHost"; - private static final String REQUEST_REALM = "requestRealm"; - - @Mock private RoutingContext routingContext; - @Mock private HttpServerRequest httpServerRequest; - @Mock private UrlConfiguration baseConfiguration; - @Mock private UrlConfiguration requestConfiguration; - - @Test - void request_configuration_is_added_correctly() { - doReturn(REQUEST_HOST).when(httpServerRequest).getHeader("Host"); - doReturn(httpServerRequest).when(routingContext).request(); - doReturn("/auth/realms/" + REQUEST_REALM).when(routingContext).normalizedPath(); - doReturn(requestConfiguration) - .when(baseConfiguration) - .forRequestContext(REQUEST_HOST, REQUEST_REALM); - RequestUrlConfigurationHandler uut = new RequestUrlConfigurationHandler(baseConfiguration); - - uut.handle(routingContext); - - verify(routingContext).put(CTX_REQUEST_CONFIGURATION, requestConfiguration); - } -} diff --git a/mock/src/test/java/com/tngtech/keycloakmock/impl/handler/TokenRouteTest.java b/mock/src/test/java/com/tngtech/keycloakmock/impl/handler/TokenRouteTest.java index 049fe0d..23fff18 100644 --- a/mock/src/test/java/com/tngtech/keycloakmock/impl/handler/TokenRouteTest.java +++ b/mock/src/test/java/com/tngtech/keycloakmock/impl/handler/TokenRouteTest.java @@ -4,6 +4,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import com.tngtech.keycloakmock.impl.UrlConfiguration; import com.tngtech.keycloakmock.impl.helper.TokenHelper; import com.tngtech.keycloakmock.impl.session.SessionRepository; import io.vertx.core.http.HttpServerRequest; @@ -28,6 +29,7 @@ class TokenRouteTest { @Mock private RoutingContext routingContext; @Mock private HttpServerRequest request; + @Mock private UrlConfiguration baseConfiguration; private TokenRoute uut; @@ -36,7 +38,7 @@ void missing_grant_type_causes_error() { doReturn(request).when(routingContext).request(); doReturn(null).when(request).getFormAttribute("grant_type"); - uut = new TokenRoute(sessionRepository, tokenHelper); + uut = new TokenRoute(sessionRepository, tokenHelper, baseConfiguration); uut.handle(routingContext); @@ -50,7 +52,7 @@ void missing_authorization_code_causes_error_for_type_authorization_code() { doReturn(AUTH_CODE_GRANT_TYPE).when(request).getFormAttribute("grant_type"); doReturn(null).when(request).getFormAttribute("code"); - uut = new TokenRoute(sessionRepository, tokenHelper); + uut = new TokenRoute(sessionRepository, tokenHelper, baseConfiguration); uut.handle(routingContext); @@ -65,7 +67,7 @@ void unknown_authorization_code_causes_error_for_type_authorization_code() { doReturn(UNKNOWN_SESSION).when(request).getFormAttribute("code"); doReturn(null).when(sessionRepository).getSession(UNKNOWN_SESSION); - uut = new TokenRoute(sessionRepository, tokenHelper); + uut = new TokenRoute(sessionRepository, tokenHelper, baseConfiguration); uut.handle(routingContext); @@ -79,7 +81,7 @@ void missing_token_causes_error_for_type_refresh_token() { doReturn(REFRESH_TOKEN_GRANT_TYPE).when(request).getFormAttribute("grant_type"); doReturn(null).when(request).getFormAttribute("refresh_token"); - uut = new TokenRoute(sessionRepository, tokenHelper); + uut = new TokenRoute(sessionRepository, tokenHelper, baseConfiguration); uut.handle(routingContext); @@ -93,7 +95,7 @@ void missing_client_id_causes_error_for_type_password() { doReturn(PASSWORD_GRANT_TYPE).when(request).getFormAttribute("grant_type"); doReturn(null).when(request).getFormAttribute("client_id"); - uut = new TokenRoute(sessionRepository, tokenHelper); + uut = new TokenRoute(sessionRepository, tokenHelper, baseConfiguration); uut.handle(routingContext); @@ -108,7 +110,7 @@ void missing_username_causes_error_for_type_password() { doReturn("myclient").when(request).getFormAttribute("client_id"); doReturn(null).when(request).getFormAttribute("username"); - uut = new TokenRoute(sessionRepository, tokenHelper); + uut = new TokenRoute(sessionRepository, tokenHelper, baseConfiguration); uut.handle(routingContext); @@ -122,7 +124,7 @@ void missing_basic_authorization_token_causes_error_for_type_client_credentials( doReturn(CLIENT_CREDENTIALS_GRANT_TYPE).when(request).getFormAttribute("grant_type"); doReturn(null).when(routingContext).user(); - uut = new TokenRoute(sessionRepository, tokenHelper); + uut = new TokenRoute(sessionRepository, tokenHelper, baseConfiguration); uut.handle(routingContext); @@ -137,7 +139,7 @@ void missing_clientId_in_basic_authorization_token_causes_error_for_type_client_ final User user = User.fromName(""); doReturn(user).when(routingContext).user(); - uut = new TokenRoute(sessionRepository, tokenHelper); + uut = new TokenRoute(sessionRepository, tokenHelper, baseConfiguration); uut.handle(routingContext); diff --git a/mock/src/test/java/com/tngtech/keycloakmock/impl/handler/WellKnownRouteTest.java b/mock/src/test/java/com/tngtech/keycloakmock/impl/handler/WellKnownRouteTest.java index ce887df..99bdffd 100644 --- a/mock/src/test/java/com/tngtech/keycloakmock/impl/handler/WellKnownRouteTest.java +++ b/mock/src/test/java/com/tngtech/keycloakmock/impl/handler/WellKnownRouteTest.java @@ -1,6 +1,5 @@ package com.tngtech.keycloakmock.impl.handler; -import static com.tngtech.keycloakmock.impl.handler.RequestUrlConfigurationHandler.CTX_REQUEST_CONFIGURATION; import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; @@ -11,9 +10,9 @@ import java.net.URISyntaxException; import java.util.Arrays; import java.util.Collections; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @@ -25,18 +24,24 @@ class WellKnownRouteTest extends HandlerTestBase { private static final String JWKS_URI = "jwksUri"; private static final String TOKEN_ENDPOINT = "tokenEndpoint"; - @Mock private UrlConfiguration urlConfiguration; + @Mock private UrlConfiguration baseConfiguration; + @Mock private UrlConfiguration contextConfiguration; - @InjectMocks private WellKnownRoute wellKnownRoute; + private WellKnownRoute wellKnownRoute; + + @BeforeEach + void setup() { + wellKnownRoute = new WellKnownRoute(baseConfiguration); + } @Test void well_known_configuration_is_complete() throws URISyntaxException { - doReturn(urlConfiguration).when(routingContext).get(CTX_REQUEST_CONFIGURATION); - doReturn(new URI(ISSUER)).when(urlConfiguration).getIssuer(); - doReturn(new URI(AUTHORIZATION_ENDPOINT)).when(urlConfiguration).getAuthorizationEndpoint(); - doReturn(new URI(END_SESSION_ENDPOINT)).when(urlConfiguration).getEndSessionEndpoint(); - doReturn(new URI(JWKS_URI)).when(urlConfiguration).getJwksUri(); - doReturn(new URI(TOKEN_ENDPOINT)).when(urlConfiguration).getTokenEndpoint(); + doReturn(contextConfiguration).when(baseConfiguration).forRequestContext(routingContext); + doReturn(new URI(ISSUER)).when(contextConfiguration).getIssuer(); + doReturn(new URI(AUTHORIZATION_ENDPOINT)).when(contextConfiguration).getAuthorizationEndpoint(); + doReturn(new URI(END_SESSION_ENDPOINT)).when(contextConfiguration).getEndSessionEndpoint(); + doReturn(new URI(JWKS_URI)).when(contextConfiguration).getJwksUri(); + doReturn(new URI(TOKEN_ENDPOINT)).when(contextConfiguration).getTokenEndpoint(); wellKnownRoute.handle(routingContext); diff --git a/standalone/build.gradle b/standalone/build.gradle index e9ed76b..7a0dad2 100644 --- a/standalone/build.gradle +++ b/standalone/build.gradle @@ -2,8 +2,8 @@ import com.github.jengelman.gradle.plugins.shadow.transformers.ApacheNoticeResou plugins { id 'application' - id 'com.github.gmazzo.buildconfig' version '5.3.5' - id 'com.github.johnrengelman.shadow' version '8.1.1' + id 'com.github.gmazzo.buildconfig' version '5.5.0' + id 'com.gradleup.shadow' version '8.3.3' } apply plugin: 'com.google.cloud.tools.jib' @@ -74,10 +74,6 @@ application { mainClass = 'com.tngtech.keycloakmock.standalone.Main' } -shadow { - mainClassName = application.mainClass.get() -} - buildConfig { buildConfigField('String', 'NAME', "\"${project.name}\"") buildConfigField('String', 'VERSION', "\"${project.version}\"")