KEYCLOAK-2028 Add test for token-minimum-time-to-live adapter option
This commit is contained in:
parent
ec180db39f
commit
72736e5e47
19 changed files with 523 additions and 66 deletions
|
@ -456,7 +456,6 @@ public class AdapterDeploymentContext {
|
||||||
public void setTurnOffChangeSessionIdOnLogin(boolean turnOffChangeSessionIdOnLogin) {
|
public void setTurnOffChangeSessionIdOnLogin(boolean turnOffChangeSessionIdOnLogin) {
|
||||||
delegate.setTurnOffChangeSessionIdOnLogin(turnOffChangeSessionIdOnLogin);
|
delegate.setTurnOffChangeSessionIdOnLogin(turnOffChangeSessionIdOnLogin);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getTokenMinimumTimeToLive() {
|
public int getTokenMinimumTimeToLive() {
|
||||||
|
@ -467,6 +466,7 @@ public class AdapterDeploymentContext {
|
||||||
public void setTokenMinimumTimeToLive(final int tokenMinimumTimeToLive) {
|
public void setTokenMinimumTimeToLive(final int tokenMinimumTimeToLive) {
|
||||||
delegate.setTokenMinimumTimeToLive(tokenMinimumTimeToLive);
|
delegate.setTokenMinimumTimeToLive(tokenMinimumTimeToLive);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected KeycloakUriBuilder getBaseBuilder(HttpFacade facade, String base) {
|
protected KeycloakUriBuilder getBaseBuilder(HttpFacade facade, String base) {
|
||||||
KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(base);
|
KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(base);
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.testsuite.adapter.filter;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
|
import javax.servlet.Filter;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.FilterConfig;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.keycloak.common.util.Time;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter to handle "special" requests to perform actions on adapter side (for example setting time offset )
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class AdapterActionsFilter implements Filter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(FilterConfig filterConfig) throws ServletException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||||
|
HttpServletResponse servletResp = (HttpServletResponse) response;
|
||||||
|
|
||||||
|
//Accept timeOffset as argument to enforce timeouts
|
||||||
|
String timeOffsetParam = request.getParameter("timeOffset");
|
||||||
|
if (timeOffsetParam != null && !timeOffsetParam.isEmpty()) {
|
||||||
|
Time.setOffset(Integer.parseInt(timeOffsetParam));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue request
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeResponse(HttpServletResponse response, String responseText) throws IOException {
|
||||||
|
PrintWriter writer = response.getWriter();
|
||||||
|
writer.println(responseText);
|
||||||
|
writer.flush();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.testsuite.adapter.page;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.keycloak.representations.AccessToken;
|
||||||
|
import org.keycloak.representations.RefreshToken;
|
||||||
|
import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
|
||||||
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
import org.openqa.selenium.WebElement;
|
||||||
|
import org.openqa.selenium.support.FindBy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public abstract class AbstractShowTokensPage extends AbstractPageWithInjectedUrl {
|
||||||
|
|
||||||
|
@FindBy(id = "accessToken")
|
||||||
|
private WebElement accessToken;
|
||||||
|
|
||||||
|
@FindBy(id = "refreshToken")
|
||||||
|
private WebElement refreshToken;
|
||||||
|
|
||||||
|
|
||||||
|
public AccessToken getAccessToken() {
|
||||||
|
try {
|
||||||
|
return JsonSerialization.readValue(accessToken.getText(), AccessToken.class);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RefreshToken getRefreshToken() {
|
||||||
|
try {
|
||||||
|
return JsonSerialization.readValue(refreshToken.getText(), RefreshToken.class);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>.
|
* @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>.
|
||||||
*/
|
*/
|
||||||
public class OfflineToken extends AbstractPageWithInjectedUrl {
|
public class OfflineToken extends AbstractShowTokensPage {
|
||||||
|
|
||||||
public static final String DEPLOYMENT_NAME = "offline-client";
|
public static final String DEPLOYMENT_NAME = "offline-client";
|
||||||
|
|
||||||
|
@ -32,35 +32,6 @@ public class OfflineToken extends AbstractPageWithInjectedUrl {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
@FindBy(id = "accessToken")
|
|
||||||
private WebElement accessToken;
|
|
||||||
|
|
||||||
@FindBy(id = "refreshToken")
|
|
||||||
private WebElement refreshToken;
|
|
||||||
|
|
||||||
@FindBy(id = "prettyToken")
|
|
||||||
private WebElement prettyToken;
|
|
||||||
|
|
||||||
|
|
||||||
public AccessToken getAccessToken() {
|
|
||||||
try {
|
|
||||||
return JsonSerialization.readValue(accessToken.getText(), AccessToken.class);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RefreshToken getRefreshToken() {
|
|
||||||
try {
|
|
||||||
return JsonSerialization.readValue(refreshToken.getText(), RefreshToken.class);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void logout() {
|
public void logout() {
|
||||||
log.info("Logging out, navigating to: " + getUriBuilder().path("/logout").build().toASCIIString());
|
log.info("Logging out, navigating to: " + getUriBuilder().path("/logout").build().toASCIIString());
|
||||||
driver.navigate().to(getUriBuilder().path("/logout").build().toASCIIString());
|
driver.navigate().to(getUriBuilder().path("/logout").build().toASCIIString());
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.testsuite.adapter.page;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import org.jboss.arquillian.container.test.api.OperateOnDeployment;
|
||||||
|
import org.jboss.arquillian.test.api.ArquillianResource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class TokenMinTTLPage extends AbstractShowTokensPage {
|
||||||
|
|
||||||
|
public static final String DEPLOYMENT_NAME = "token-min-ttl";
|
||||||
|
|
||||||
|
@ArquillianResource
|
||||||
|
@OperateOnDeployment(DEPLOYMENT_NAME)
|
||||||
|
private URL url;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URL getInjectedUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.testsuite.adapter.servlet;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServlet;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.keycloak.KeycloakSecurityContext;
|
||||||
|
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||||
|
import org.keycloak.jose.jws.JWSInput;
|
||||||
|
import org.keycloak.jose.jws.JWSInputException;
|
||||||
|
import org.keycloak.representations.RefreshToken;
|
||||||
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public abstract class AbstractShowTokensServlet extends HttpServlet {
|
||||||
|
|
||||||
|
private static final String LINK = "<a href=\"%s\" id=\"%s\">%s</a>";
|
||||||
|
|
||||||
|
protected String renderTokens(HttpServletRequest req) throws ServletException, IOException {
|
||||||
|
RefreshableKeycloakSecurityContext ctx = (RefreshableKeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
|
||||||
|
String accessTokenPretty = JsonSerialization.writeValueAsPrettyString(ctx.getToken());
|
||||||
|
RefreshToken refreshToken;
|
||||||
|
try {
|
||||||
|
refreshToken = new JWSInput(ctx.getRefreshToken()).readJsonContent(RefreshToken.class);
|
||||||
|
} catch (JWSInputException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
String refreshTokenPretty = JsonSerialization.writeValueAsPrettyString(refreshToken);
|
||||||
|
|
||||||
|
return new StringBuilder("<span id=\"accessToken\">" + accessTokenPretty + "</span>")
|
||||||
|
.append("<span id=\"refreshToken\">" + refreshTokenPretty + "</span>")
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -3,14 +3,12 @@ package org.keycloak.testsuite.adapter.servlet;
|
||||||
import org.keycloak.KeycloakSecurityContext;
|
import org.keycloak.KeycloakSecurityContext;
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
|
||||||
import org.keycloak.common.util.Time;
|
|
||||||
import org.keycloak.jose.jws.JWSInput;
|
import org.keycloak.jose.jws.JWSInput;
|
||||||
import org.keycloak.jose.jws.JWSInputException;
|
import org.keycloak.jose.jws.JWSInputException;
|
||||||
import org.keycloak.representations.RefreshToken;
|
import org.keycloak.representations.RefreshToken;
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServlet;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.ws.rs.core.UriBuilder;
|
import javax.ws.rs.core.UriBuilder;
|
||||||
|
@ -19,7 +17,7 @@ import java.io.IOException;
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
*/
|
*/
|
||||||
public class OfflineTokenServlet extends HttpServlet {
|
public class OfflineTokenServlet extends AbstractShowTokensServlet {
|
||||||
|
|
||||||
private static final String OFFLINE_CLIENT_APP_URI = (System.getProperty("app.server.ssl.required", "false").equals("true")) ?
|
private static final String OFFLINE_CLIENT_APP_URI = (System.getProperty("app.server.ssl.required", "false").equals("true")) ?
|
||||||
System.getProperty("app.server.ssl.base.url", "https://localhost:8643") + "/offline-client" :
|
System.getProperty("app.server.ssl.base.url", "https://localhost:8643") + "/offline-client" :
|
||||||
|
@ -31,12 +29,6 @@ public class OfflineTokenServlet extends HttpServlet {
|
||||||
@Override
|
@Override
|
||||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
|
|
||||||
//Accept timeOffset as argument to enforce timeouts
|
|
||||||
String timeOffsetParam = req.getParameter("timeOffset");
|
|
||||||
if (timeOffsetParam != null && !timeOffsetParam.isEmpty()) {
|
|
||||||
Time.setOffset(Integer.parseInt(timeOffsetParam));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req.getRequestURI().endsWith("logout")) {
|
if (req.getRequestURI().endsWith("logout")) {
|
||||||
|
|
||||||
UriBuilder redirectUriBuilder = UriBuilder.fromUri(OFFLINE_CLIENT_APP_URI);
|
UriBuilder redirectUriBuilder = UriBuilder.fromUri(OFFLINE_CLIENT_APP_URI);
|
||||||
|
@ -54,19 +46,11 @@ public class OfflineTokenServlet extends HttpServlet {
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder response = new StringBuilder("<html><head><title>Offline token servlet</title></head><body><pre>");
|
StringBuilder response = new StringBuilder("<html><head><title>Offline token servlet</title></head><body><pre>");
|
||||||
RefreshableKeycloakSecurityContext ctx = (RefreshableKeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
|
|
||||||
String accessTokenPretty = JsonSerialization.writeValueAsPrettyString(ctx.getToken());
|
|
||||||
RefreshToken refreshToken;
|
|
||||||
try {
|
|
||||||
refreshToken = new JWSInput(ctx.getRefreshToken()).readJsonContent(RefreshToken.class);
|
|
||||||
} catch (JWSInputException e) {
|
|
||||||
throw new IOException(e);
|
|
||||||
}
|
|
||||||
String refreshTokenPretty = JsonSerialization.writeValueAsPrettyString(refreshToken);
|
|
||||||
|
|
||||||
response = response.append("<span id=\"accessToken\">" + accessTokenPretty + "</span>")
|
String tokens = renderTokens(req);
|
||||||
.append("<span id=\"refreshToken\">" + refreshTokenPretty + "</span>")
|
response = response.append(tokens);
|
||||||
.append("</pre></body></html>");
|
|
||||||
|
response.append("</pre></body></html>");
|
||||||
resp.getWriter().println(response.toString());
|
resp.getWriter().println(response.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
* and other contributors as indicated by the @author tags.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.keycloak.testsuite.adapter.servlet;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class TokenMinTTLServlet extends AbstractShowTokensServlet {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
|
StringBuilder response = new StringBuilder("<html><head><title>Token Min TTL Servlet</title></head><body><pre>");
|
||||||
|
|
||||||
|
String tokens = renderTokens(req);
|
||||||
|
response = response.append(tokens);
|
||||||
|
|
||||||
|
response.append("</pre></body></html>");
|
||||||
|
resp.getWriter().println(response.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ import org.jboss.logging.Logger.Level;
|
||||||
import org.jboss.shrinkwrap.api.Archive;
|
import org.jboss.shrinkwrap.api.Archive;
|
||||||
import org.jboss.shrinkwrap.api.asset.StringAsset;
|
import org.jboss.shrinkwrap.api.asset.StringAsset;
|
||||||
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
||||||
|
import org.keycloak.representations.adapters.config.AdapterConfig;
|
||||||
import org.keycloak.representations.adapters.config.BaseAdapterConfig;
|
import org.keycloak.representations.adapters.config.BaseAdapterConfig;
|
||||||
import org.keycloak.testsuite.adapter.AdapterLibsMode;
|
import org.keycloak.testsuite.adapter.AdapterLibsMode;
|
||||||
import org.keycloak.testsuite.util.IOUtil;
|
import org.keycloak.testsuite.util.IOUtil;
|
||||||
|
@ -118,8 +119,8 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
|
||||||
}
|
}
|
||||||
} else { // OIDC adapter config
|
} else { // OIDC adapter config
|
||||||
try {
|
try {
|
||||||
BaseAdapterConfig adapterConfig = loadJson(archive.get(adapterConfigPath)
|
AdapterConfig adapterConfig = loadJson(archive.get(adapterConfigPath)
|
||||||
.getAsset().openStream(), BaseAdapterConfig.class);
|
.getAsset().openStream(), AdapterConfig.class);
|
||||||
|
|
||||||
log.info(" setting " + (relative ? "" : "non-") + "relative auth-server-url");
|
log.info(" setting " + (relative ? "" : "non-") + "relative auth-server-url");
|
||||||
if (relative) {
|
if (relative) {
|
||||||
|
|
|
@ -22,11 +22,15 @@ import org.jboss.shrinkwrap.api.ShrinkWrap;
|
||||||
import org.jboss.shrinkwrap.api.asset.StringAsset;
|
import org.jboss.shrinkwrap.api.asset.StringAsset;
|
||||||
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
import org.jboss.shrinkwrap.api.spec.WebArchive;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
import org.keycloak.testsuite.util.WaitUtils;
|
||||||
|
import org.openqa.selenium.By;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.UriBuilder;
|
||||||
|
|
||||||
import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO;
|
import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO;
|
||||||
import static org.keycloak.testsuite.util.IOUtil.loadRealm;
|
import static org.keycloak.testsuite.util.IOUtil.loadRealm;
|
||||||
|
|
||||||
|
@ -107,4 +111,14 @@ public abstract class AbstractServletsAdapterTest extends AbstractAdapterTest {
|
||||||
testRealmPage.setAuthRealm(DEMO);
|
testRealmPage.setAuthRealm(DEMO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void setAdapterAndServerTimeOffset(int timeOffset, String servletUri) {
|
||||||
|
setTimeOffset(timeOffset);
|
||||||
|
String timeOffsetUri = UriBuilder.fromUri(servletUri)
|
||||||
|
.queryParam("timeOffset", timeOffset)
|
||||||
|
.build().toString();
|
||||||
|
|
||||||
|
driver.navigate().to(timeOffsetUri);
|
||||||
|
WaitUtils.waitUntilElement(By.tagName("body")).is().visible();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,11 @@ import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.common.Version;
|
import org.keycloak.common.Version;
|
||||||
import org.keycloak.constants.AdapterConstants;
|
import org.keycloak.constants.AdapterConstants;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
|
||||||
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.representations.VersionRepresentation;
|
import org.keycloak.representations.VersionRepresentation;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
|
import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
|
||||||
|
import org.keycloak.testsuite.adapter.filter.AdapterActionsFilter;
|
||||||
import org.keycloak.testsuite.adapter.page.*;
|
import org.keycloak.testsuite.adapter.page.*;
|
||||||
import org.keycloak.util.BasicAuthHelper;
|
import org.keycloak.util.BasicAuthHelper;
|
||||||
|
|
||||||
|
@ -70,6 +72,8 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
|
||||||
private ProductPortal productPortal;
|
private ProductPortal productPortal;
|
||||||
@Page
|
@Page
|
||||||
private InputPortal inputPortal;
|
private InputPortal inputPortal;
|
||||||
|
@Page
|
||||||
|
private TokenMinTTLPage tokenMinTTLPage;
|
||||||
|
|
||||||
@Deployment(name = CustomerPortal.DEPLOYMENT_NAME)
|
@Deployment(name = CustomerPortal.DEPLOYMENT_NAME)
|
||||||
protected static WebArchive customerPortal() {
|
protected static WebArchive customerPortal() {
|
||||||
|
@ -106,6 +110,11 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
|
||||||
return servletDeployment(InputPortal.DEPLOYMENT_NAME, "keycloak.json", InputServlet.class);
|
return servletDeployment(InputPortal.DEPLOYMENT_NAME, "keycloak.json", InputServlet.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deployment(name = TokenMinTTLPage.DEPLOYMENT_NAME)
|
||||||
|
protected static WebArchive tokenMinTTLPage() {
|
||||||
|
return servletDeployment(TokenMinTTLPage.DEPLOYMENT_NAME, AdapterActionsFilter.class, AbstractShowTokensServlet.class, TokenMinTTLServlet.class, ErrorServlet.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCustomerPortalWithSubsystemSettings() {
|
public void testCustomerPortalWithSubsystemSettings() {
|
||||||
customerPortalSubsystem.navigateTo();
|
customerPortalSubsystem.navigateTo();
|
||||||
|
@ -408,4 +417,36 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
|
||||||
assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
|
assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests "token-minimum-time-to-live" adapter configuration option
|
||||||
|
@Test
|
||||||
|
public void testTokenMinTTL() {
|
||||||
|
// Login
|
||||||
|
tokenMinTTLPage.navigateTo();
|
||||||
|
testRealmLoginPage.form().waitForUsernameInputPresent();
|
||||||
|
assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
|
||||||
|
testRealmLoginPage.form().login("bburke@redhat.com", "password");
|
||||||
|
assertCurrentUrlEquals(tokenMinTTLPage);
|
||||||
|
|
||||||
|
// Get time of token
|
||||||
|
AccessToken token = tokenMinTTLPage.getAccessToken();
|
||||||
|
int tokenIssued1 = token.getIssuedAt();
|
||||||
|
|
||||||
|
// Sets 5 minutes offset and assert access token will be still the same
|
||||||
|
setAdapterAndServerTimeOffset(300, tokenMinTTLPage.toString());
|
||||||
|
token = tokenMinTTLPage.getAccessToken();
|
||||||
|
int tokenIssued2 = token.getIssuedAt();
|
||||||
|
Assert.assertEquals(tokenIssued1, tokenIssued2);
|
||||||
|
Assert.assertFalse(token.isExpired());
|
||||||
|
|
||||||
|
// Sets 9 minutes offset and assert access token will be refreshed (accessTokenTimeout is 10 minutes, token-min-ttl is 2 minutes. Hence 8 minutes or more should be sufficient)
|
||||||
|
setAdapterAndServerTimeOffset(540, tokenMinTTLPage.toString());
|
||||||
|
token = tokenMinTTLPage.getAccessToken();
|
||||||
|
int tokenIssued3 = token.getIssuedAt();
|
||||||
|
Assert.assertTrue(tokenIssued3 > tokenIssued1);
|
||||||
|
|
||||||
|
// Revert times
|
||||||
|
setAdapterAndServerTimeOffset(0, tokenMinTTLPage.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import org.keycloak.events.EventType;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.testsuite.AssertEvents;
|
import org.keycloak.testsuite.AssertEvents;
|
||||||
import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
|
import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
|
||||||
|
import org.keycloak.testsuite.adapter.filter.AdapterActionsFilter;
|
||||||
import org.keycloak.testsuite.adapter.page.OfflineToken;
|
import org.keycloak.testsuite.adapter.page.OfflineToken;
|
||||||
import org.keycloak.testsuite.pages.AccountApplicationsPage;
|
import org.keycloak.testsuite.pages.AccountApplicationsPage;
|
||||||
import org.keycloak.testsuite.pages.LoginPage;
|
import org.keycloak.testsuite.pages.LoginPage;
|
||||||
|
@ -48,7 +49,7 @@ public abstract class AbstractOfflineServletsAdapterTest extends AbstractServlet
|
||||||
|
|
||||||
@Deployment(name = OfflineToken.DEPLOYMENT_NAME)
|
@Deployment(name = OfflineToken.DEPLOYMENT_NAME)
|
||||||
protected static WebArchive offlineClient() {
|
protected static WebArchive offlineClient() {
|
||||||
return servletDeployment(OfflineToken.DEPLOYMENT_NAME, OfflineTokenServlet.class, ErrorServlet.class);
|
return servletDeployment(OfflineToken.DEPLOYMENT_NAME, AdapterActionsFilter.class, AbstractShowTokensServlet.class, OfflineTokenServlet.class, ErrorServlet.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -186,14 +187,7 @@ public abstract class AbstractOfflineServletsAdapterTest extends AbstractServlet
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setAdapterAndServerTimeOffset(int timeOffset) {
|
private void setAdapterAndServerTimeOffset(int timeOffset) {
|
||||||
setTimeOffset(timeOffset);
|
super.setAdapterAndServerTimeOffset(timeOffset, offlineTokenPage.toString());
|
||||||
String timeOffsetUri = UriBuilder.fromUri(offlineTokenPage.toString())
|
|
||||||
.queryParam("timeOffset", timeOffset)
|
|
||||||
.build().toString();
|
|
||||||
|
|
||||||
driver.navigate().to(timeOffsetUri);
|
|
||||||
waitUntilElement(By.tagName("body")).is().visible();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"id": "demo",
|
"id": "demo",
|
||||||
"realm": "demo",
|
"realm": "demo",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"accessTokenLifespan": 3000,
|
"accessTokenLifespan": 600,
|
||||||
"accessCodeLifespan": 10,
|
"accessCodeLifespan": 10,
|
||||||
"accessCodeLifespanUserAction": 6000,
|
"accessCodeLifespanUserAction": 6000,
|
||||||
"sslRequired": "external",
|
"sslRequired": "external",
|
||||||
|
@ -208,6 +208,16 @@
|
||||||
],
|
],
|
||||||
"secret": "password"
|
"secret": "password"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"clientId": "token-min-ttl",
|
||||||
|
"enabled": true,
|
||||||
|
"adminUrl": "/token-min-ttl",
|
||||||
|
"baseUrl": "/token-min-ttl",
|
||||||
|
"redirectUris": [
|
||||||
|
"/token-min-ttl/*"
|
||||||
|
],
|
||||||
|
"secret": "password"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"clientId": "third-party",
|
"clientId": "third-party",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
|
|
|
@ -23,6 +23,11 @@
|
||||||
|
|
||||||
<module-name>offline-client</module-name>
|
<module-name>offline-client</module-name>
|
||||||
|
|
||||||
|
<filter>
|
||||||
|
<filter-name>AdapterActionsFilter</filter-name>
|
||||||
|
<filter-class>org.keycloak.testsuite.adapter.filter.AdapterActionsFilter</filter-class>
|
||||||
|
</filter>
|
||||||
|
|
||||||
<servlet>
|
<servlet>
|
||||||
<servlet-name>Servlet</servlet-name>
|
<servlet-name>Servlet</servlet-name>
|
||||||
<servlet-class>org.keycloak.testsuite.adapter.servlet.OfflineTokenServlet</servlet-class>
|
<servlet-class>org.keycloak.testsuite.adapter.servlet.OfflineTokenServlet</servlet-class>
|
||||||
|
@ -33,6 +38,11 @@
|
||||||
<servlet-class>org.keycloak.testsuite.adapter.servlet.ErrorServlet</servlet-class>
|
<servlet-class>org.keycloak.testsuite.adapter.servlet.ErrorServlet</servlet-class>
|
||||||
</servlet>
|
</servlet>
|
||||||
|
|
||||||
|
<filter-mapping>
|
||||||
|
<filter-name>AdapterActionsFilter</filter-name>
|
||||||
|
<url-pattern>/*</url-pattern>
|
||||||
|
</filter-mapping>
|
||||||
|
|
||||||
<servlet-mapping>
|
<servlet-mapping>
|
||||||
<servlet-name>Servlet</servlet-name>
|
<servlet-name>Servlet</servlet-name>
|
||||||
<url-pattern>/*</url-pattern>
|
<url-pattern>/*</url-pattern>
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!--
|
||||||
|
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
~ and other contributors as indicated by the @author tags.
|
||||||
|
~
|
||||||
|
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
~ you may not use this file except in compliance with the License.
|
||||||
|
~ You may obtain a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
~ See the License for the specific language governing permissions and
|
||||||
|
~ limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<Context path="/token-min-ttl">
|
||||||
|
<Valve className="org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve"/>
|
||||||
|
</Context>
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
~ and other contributors as indicated by the @author tags.
|
||||||
|
~
|
||||||
|
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
~ you may not use this file except in compliance with the License.
|
||||||
|
~ You may obtain a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
~ See the License for the specific language governing permissions and
|
||||||
|
~ limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
|
||||||
|
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
|
||||||
|
<Get name="securityHandler">
|
||||||
|
<Set name="authenticator">
|
||||||
|
<New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
|
||||||
|
<!--
|
||||||
|
<Set name="adapterConfig">
|
||||||
|
<New class="org.keycloak.representations.adapters.config.AdapterConfig">
|
||||||
|
<Set name="realm">tomcat</Set>
|
||||||
|
<Set name="resource">customer-portal</Set>
|
||||||
|
<Set name="authServerUrl">http://localhost:8180/auth</Set>
|
||||||
|
<Set name="sslRequired">external</Set>
|
||||||
|
<Set name="credentials">
|
||||||
|
<Map>
|
||||||
|
<Entry>
|
||||||
|
<Item>secret</Item>
|
||||||
|
<Item>password</Item>
|
||||||
|
</Entry>
|
||||||
|
</Map>
|
||||||
|
</Set>
|
||||||
|
<Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
|
||||||
|
</New>
|
||||||
|
</Set>
|
||||||
|
-->
|
||||||
|
</New>
|
||||||
|
</Set>
|
||||||
|
</Get>
|
||||||
|
</Configure>
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"realm": "demo",
|
||||||
|
"resource": "token-min-ttl",
|
||||||
|
"realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||||
|
"auth-server-url": "http://localhost:8180/auth",
|
||||||
|
"ssl-required" : "external",
|
||||||
|
"credentials": {
|
||||||
|
"secret": "password"
|
||||||
|
},
|
||||||
|
"token-minimum-time-to-live": 120
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||||
|
~ and other contributors as indicated by the @author tags.
|
||||||
|
~
|
||||||
|
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
~ you may not use this file except in compliance with the License.
|
||||||
|
~ You may obtain a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
~ See the License for the specific language governing permissions and
|
||||||
|
~ limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
|
||||||
|
version="3.0">
|
||||||
|
|
||||||
|
<module-name>token-min-ttl</module-name>
|
||||||
|
|
||||||
|
<filter>
|
||||||
|
<filter-name>AdapterActionsFilter</filter-name>
|
||||||
|
<filter-class>org.keycloak.testsuite.adapter.filter.AdapterActionsFilter</filter-class>
|
||||||
|
</filter>
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>Servlet</servlet-name>
|
||||||
|
<servlet-class>org.keycloak.testsuite.adapter.servlet.TokenMinTTLServlet</servlet-class>
|
||||||
|
</servlet>
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>Error Servlet</servlet-name>
|
||||||
|
<servlet-class>org.keycloak.testsuite.adapter.servlet.ErrorServlet</servlet-class>
|
||||||
|
</servlet>
|
||||||
|
|
||||||
|
<filter-mapping>
|
||||||
|
<filter-name>AdapterActionsFilter</filter-name>
|
||||||
|
<url-pattern>/*</url-pattern>
|
||||||
|
</filter-mapping>
|
||||||
|
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>Servlet</servlet-name>
|
||||||
|
<url-pattern>/*</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>Error Servlet</servlet-name>
|
||||||
|
<url-pattern>/error.html</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<security-constraint>
|
||||||
|
<web-resource-collection>
|
||||||
|
<web-resource-name>Users</web-resource-name>
|
||||||
|
<url-pattern>/*</url-pattern>
|
||||||
|
</web-resource-collection>
|
||||||
|
<auth-constraint>
|
||||||
|
<role-name>user</role-name>
|
||||||
|
</auth-constraint>
|
||||||
|
</security-constraint>
|
||||||
|
<security-constraint>
|
||||||
|
<web-resource-collection>
|
||||||
|
<web-resource-name>Errors</web-resource-name>
|
||||||
|
<url-pattern>/error.html</url-pattern>
|
||||||
|
</web-resource-collection>
|
||||||
|
</security-constraint>
|
||||||
|
|
||||||
|
<login-config>
|
||||||
|
<auth-method>KEYCLOAK</auth-method>
|
||||||
|
<realm-name>test</realm-name>
|
||||||
|
<form-login-config>
|
||||||
|
<form-login-page>/error.html</form-login-page>
|
||||||
|
<form-error-page>/error.html</form-error-page>
|
||||||
|
</form-login-config>
|
||||||
|
</login-config>
|
||||||
|
|
||||||
|
<security-role>
|
||||||
|
<role-name>admin</role-name>
|
||||||
|
</security-role>
|
||||||
|
<security-role>
|
||||||
|
<role-name>user</role-name>
|
||||||
|
</security-role>
|
||||||
|
</web-app>
|
|
@ -8,6 +8,5 @@
|
||||||
"token-store": "cookie",
|
"token-store": "cookie",
|
||||||
"credentials": {
|
"credentials": {
|
||||||
"secret": "password"
|
"secret": "password"
|
||||||
},
|
}
|
||||||
"token-minimum-time-to-live": 1
|
|
||||||
}
|
}
|
Loading…
Reference in a new issue