/*
* 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.admin;
import org.jboss.arquillian.graphene.page.Page;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.UserSessionRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.pages.ConsentPage;
import org.keycloak.testsuite.pages.LoginPage;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient;
import static org.keycloak.testsuite.admin.ApiUtil.resetUserPassword;
/**
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
*/
public class ConsentsTest extends AbstractKeycloakTest {
final static String REALM_PROV_NAME = "provider";
final static String REALM_CONS_NAME = "consumer";
final static String IDP_OIDC_ALIAS = "kc-oidc-idp";
final static String IDP_OIDC_PROVIDER_ID = "keycloak-oidc";
final static String CLIENT_ID = "brokerapp";
final static String CLIENT_SECRET = "secret";
final static String USER_LOGIN = "testuser";
final static String USER_EMAIL = "user@localhost.com";
final static String USER_PASSWORD = "password";
final static String USER_FIRSTNAME = "User";
final static String USER_LASTNAME = "Tester";
protected RealmRepresentation createProviderRealm() {
RealmRepresentation realm = new RealmRepresentation();
realm.setRealm(REALM_PROV_NAME);
realm.setEnabled(true);
return realm;
}
protected RealmRepresentation createConsumerRealm() {
RealmRepresentation realm = new RealmRepresentation();
realm.setRealm(REALM_CONS_NAME);
realm.setEnabled(true);
return realm;
}
protected List<ClientRepresentation> createProviderClients() {
ClientRepresentation client = new ClientRepresentation();
client.setId(CLIENT_ID);
client.setName(CLIENT_ID);
client.setSecret(CLIENT_SECRET);
client.setEnabled(true);
client.setConsentRequired(true);
client.setRedirectUris(Collections.singletonList(getAuthRoot() +
"/auth/realms/" + REALM_CONS_NAME + "/broker/" + IDP_OIDC_ALIAS + "/endpoint/*"));
client.setAdminUrl(getAuthRoot() +
"/auth/realms/" + REALM_CONS_NAME + "/broker/" + IDP_OIDC_ALIAS + "/endpoint");
return Collections.singletonList(client);
}
protected IdentityProviderRepresentation setUpIdentityProvider() {
IdentityProviderRepresentation idp = createIdentityProvider(IDP_OIDC_ALIAS, IDP_OIDC_PROVIDER_ID);
Map<String, String> config = idp.getConfig();
config.put("clientId", CLIENT_ID);
config.put("clientSecret", CLIENT_SECRET);
config.put("prompt", "login");
config.put("authorizationUrl", getAuthRoot() + "/auth/realms/" + REALM_PROV_NAME + "/protocol/openid-connect/auth");
config.put("tokenUrl", getAuthRoot() + "/auth/realms/" + REALM_PROV_NAME + "/protocol/openid-connect/token");
config.put("logoutUrl", getAuthRoot() + "/auth/realms/" + REALM_PROV_NAME + "/protocol/openid-connect/logout");
config.put("userInfoUrl", getAuthRoot() + "/auth/realms/" + REALM_PROV_NAME + "/protocol/openid-connect/userinfo");
config.put("defaultScope", "email profile");
config.put("backchannelSupported", "true");
return idp;
}
protected String getUserLogin() {
return USER_LOGIN;
}
protected String getUserPassword() {
return USER_PASSWORD;
}
protected String getUserEmail() {
return USER_EMAIL;
}
protected String getUserFirstName() {
return USER_FIRSTNAME;
}
protected String getUserLastName() {
return USER_LASTNAME;
}
protected String providerRealmName() {
return REALM_PROV_NAME;
}
protected String consumerRealmName() {
return REALM_CONS_NAME;
}
protected String getIDPAlias() {
return IDP_OIDC_ALIAS;
}
@Page
protected LoginPage accountLoginPage;
@Page
protected ConsentPage consentPage;
@Override
public void addTestRealms(List<RealmRepresentation> testRealms) {
RealmRepresentation providerRealm = createProviderRealm();
RealmRepresentation consumerRealm = createConsumerRealm();
testRealms.add(providerRealm);
testRealms.add(consumerRealm);
}
@Before
public void createUser() {
log.debug("creating user for realm " + providerRealmName());
UserRepresentation user = new UserRepresentation();
user.setUsername(getUserLogin());
user.setEmail(getUserEmail());
user.setFirstName(getUserFirstName());
user.setLastName(getUserLastName());
user.setEmailVerified(true);
user.setEnabled(true);
RealmResource realmResource = adminClient.realm(providerRealmName());
String userId = createUserWithAdminClient(realmResource, user);
resetUserPassword(realmResource.users().get(userId), getUserPassword(), false);
}
@Before
public void addIdentityProviderToProviderRealm() {
log.debug("adding identity provider to realm " + consumerRealmName());
RealmResource realm = adminClient.realm(consumerRealmName());
realm.identityProviders().create(setUpIdentityProvider());
}
@Before
public void addClients() {
List<ClientRepresentation> clients = createProviderClients();
if (clients != null) {
RealmResource providerRealm = adminClient.realm(providerRealmName());
for (ClientRepresentation client : clients) {
log.debug("adding client " + client.getName() + " to realm " + providerRealmName());
providerRealm.clients().create(client);
}
}
}
protected String getAuthRoot() {
return suiteContext.getAuthServerInfo().getContextRoot().toString();
}
protected IdentityProviderRepresentation createIdentityProvider(String alias, String providerId) {
IdentityProviderRepresentation identityProviderRepresentation = new IdentityProviderRepresentation();
identityProviderRepresentation.setAlias(alias);
identityProviderRepresentation.setDisplayName(providerId);
identityProviderRepresentation.setProviderId(providerId);
identityProviderRepresentation.setEnabled(true);
return identityProviderRepresentation;
}
private void waitForPage(String title) {
long startAt = System.currentTimeMillis();
while (!driver.getTitle().toLowerCase().contains(title)
&& System.currentTimeMillis() - startAt < 200) {
try {
Thread.sleep(5);
} catch (InterruptedException ignore) {}
}
}
@Test
public void testConsents() {
driver.navigate().to(getAccountUrl(consumerRealmName()));
log.debug("Clicking social " + getIDPAlias());
accountLoginPage.clickSocial(getIDPAlias());
if (!driver.getCurrentUrl().contains("/auth/realms/" + providerRealmName() + "/")) {
log.debug("Not on provider realm page, url: " + driver.getCurrentUrl());
}
Assert.assertTrue("Driver should be on the provider realm page right now",
driver.getCurrentUrl().contains("/auth/realms/" + providerRealmName() + "/"));
log.debug("Logging in");
accountLoginPage.login(getUserLogin(), getUserPassword());
waitForPage("grant access");
Assert.assertTrue(consentPage.isCurrent());
consentPage.confirm();
Assert.assertTrue("We must be on correct realm right now",
driver.getCurrentUrl().contains("/auth/realms/" + consumerRealmName() + "/"));
UsersResource consumerUsers = adminClient.realm(consumerRealmName()).users();
Assert.assertTrue("There must be at least one user", consumerUsers.count() > 0);
List<UserRepresentation> users = consumerUsers.search("", 0, 5);
UserRepresentation foundUser = null;
for (UserRepresentation user : users) {
if (user.getUsername().equals(getUserLogin()) && user.getEmail().equals(getUserEmail())) {
foundUser = user;
break;
}
}
Assert.assertNotNull("There must be user " + getUserLogin() + " in realm " + consumerRealmName(),
foundUser);
// get user with the same username from provider realm
RealmResource providerRealm = adminClient.realm(providerRealmName());
users = providerRealm.users().search(null, foundUser.getFirstName(), foundUser.getLastName(), null, 0, 1);
Assert.assertEquals("Same user should be in provider realm", 1, users.size());
String userId = users.get(0).getId();
UserResource userResource = providerRealm.users().get(userId);
// list consents
List<Map<String, Object>> consents = userResource.getConsents();
Assert.assertEquals("There should be one consent", 1, consents.size());
Map<String, Object> consent = consents.get(0);
Assert.assertEquals("Consent should be given to " + CLIENT_ID, CLIENT_ID, consent.get("clientId"));
// list sessions
List<UserSessionRepresentation> sessions = userResource.getUserSessions();
Assert.assertEquals("There should be one active session", 1, sessions.size());
// revoke consent
userResource.revokeConsent(CLIENT_ID);
// list consents
consents = userResource.getConsents();
Assert.assertEquals("There should be no consents", 0, consents.size());
// list sessions
sessions = userResource.getUserSessions();
Assert.assertEquals("There should be no active session", 0, sessions.size());
}
private String getAccountUrl(String realmName) {
return getAuthRoot() + "/auth/realms/" + realmName + "/account";
}
}