/*
* 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.oauth;
import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.junit.Test;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.models.Constants;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class LoginStatusIframeEndpointTest extends AbstractKeycloakTest {
@Test
public void checkIframe() throws IOException {
CookieStore cookieStore = new BasicCookieStore();
CloseableHttpClient client = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
try {
String redirectUri = URLEncoder.encode(suiteContext.getAuthServerInfo().getContextRoot() + "/auth/admin/master/console", "UTF-8");
HttpGet get = new HttpGet(
suiteContext.getAuthServerInfo().getContextRoot() + "/auth/realms/master/protocol/openid-connect/auth?response_type=code&client_id=" + Constants.ADMIN_CONSOLE_CLIENT_ID +
"&redirect_uri=" + redirectUri);
CloseableHttpResponse response = client.execute(get);
String s = IOUtils.toString(response.getEntity().getContent());
response.close();
Matcher matcher = Pattern.compile("action=\"([^\"]*)\"").matcher(s);
matcher.find();
String action = matcher.group(1);
HttpPost post = new HttpPost(action);
List<NameValuePair> params = new LinkedList<>();
params.add(new BasicNameValuePair("username", "admin"));
params.add(new BasicNameValuePair("password", "admin"));
post.setHeader("Content-Type", "application/x-www-form-urlencoded");
post.setEntity(new UrlEncodedFormEntity(params));
response = client.execute(post);
assertEquals("CP=\"This is not a P3P policy!\"", response.getFirstHeader("P3P").getValue());
Header setIdentityCookieHeader = null;
Header setSessionCookieHeader = null;
for (Header h : response.getAllHeaders()) {
if (h.getName().equals("Set-Cookie")) {
if (h.getValue().contains("KEYCLOAK_SESSION")) {
setSessionCookieHeader = h;
} else if (h.getValue().contains("KEYCLOAK_IDENTITY")) {
setIdentityCookieHeader = h;
}
}
}
assertNotNull(setIdentityCookieHeader);
assertTrue(setIdentityCookieHeader.getValue().contains("HttpOnly"));
assertNotNull(setSessionCookieHeader);
assertFalse(setSessionCookieHeader.getValue().contains("HttpOnly"));
response.close();
Cookie sessionCookie = null;
for (Cookie cookie : cookieStore.getCookies()) {
if (cookie.getName().equals("KEYCLOAK_SESSION")) {
sessionCookie = cookie;
break;
}
}
assertNotNull(sessionCookie);
get = new HttpGet(suiteContext.getAuthServerInfo().getContextRoot() + "/auth/realms/master/protocol/openid-connect/login-status-iframe.html");
response = client.execute(get);
assertEquals(200, response.getStatusLine().getStatusCode());
s = IOUtils.toString(response.getEntity().getContent());
assertTrue(s.contains("function getCookie()"));
assertEquals("CP=\"This is not a P3P policy!\"", response.getFirstHeader("P3P").getValue());
response.close();
get = new HttpGet(suiteContext.getAuthServerInfo().getContextRoot() + "/auth/realms/master/protocol/openid-connect/login-status-iframe.html/init");
response = client.execute(get);
assertEquals(403, response.getStatusLine().getStatusCode());
response.close();
get = new HttpGet(suiteContext.getAuthServerInfo().getContextRoot() + "/auth/realms/master/protocol/openid-connect/login-status-iframe.html/init?"
+ "client_id=invalid"
+ "&origin=" + suiteContext.getAuthServerInfo().getContextRoot()
);
response = client.execute(get);
assertEquals(403, response.getStatusLine().getStatusCode());
response.close();
get = new HttpGet(suiteContext.getAuthServerInfo().getContextRoot() + "/auth/realms/master/protocol/openid-connect/login-status-iframe.html/init?"
+ "client_id=" + Constants.ADMIN_CONSOLE_CLIENT_ID
+ "&origin=http://invalid"
);
response = client.execute(get);
assertEquals(403, response.getStatusLine().getStatusCode());
response.close();
get = new HttpGet(suiteContext.getAuthServerInfo().getContextRoot() + "/auth/realms/master/protocol/openid-connect/login-status-iframe.html/init?"
+ "client_id=" + Constants.ADMIN_CONSOLE_CLIENT_ID
+ "&origin=" + suiteContext.getAuthServerInfo().getContextRoot()
);
response = client.execute(get);
assertEquals(204, response.getStatusLine().getStatusCode());
response.close();
} finally {
client.close();
}
}
@Test
public void checkIframeWildcardOrigin() throws IOException {
String id = adminClient.realm("master").clients().findByClientId(Constants.ADMIN_CONSOLE_CLIENT_ID).get(0).getId();
ClientResource master = adminClient.realm("master").clients().get(id);
ClientRepresentation rep = master.toRepresentation();
List<String> org = rep.getWebOrigins();
CloseableHttpClient client = HttpClients.createDefault();
try {
rep.setWebOrigins(Collections.singletonList("*"));
master.update(rep);
HttpGet get = new HttpGet(suiteContext.getAuthServerInfo().getContextRoot() + "/auth/realms/master/protocol/openid-connect/login-status-iframe.html/init?"
+ "client_id=" + Constants.ADMIN_CONSOLE_CLIENT_ID
+ "&origin=" + "http://anything"
);
CloseableHttpResponse response = client.execute(get);
assertEquals(204, response.getStatusLine().getStatusCode());
response.close();
} finally {
rep.setWebOrigins(org);
master.update(rep);
client.close();
}
}
@Override
public void addTestRealms(List<RealmRepresentation> testRealms) {
}
}