KEYCLOAK-10457 Merge preview features test: SocialLoginTest
This commit is contained in:
parent
5d44c7938a
commit
925864530a
1 changed files with 136 additions and 112 deletions
|
@ -28,6 +28,7 @@ import org.keycloak.services.resources.admin.permissions.AdminPermissionManageme
|
||||||
import org.keycloak.services.resources.admin.permissions.AdminPermissions;
|
import org.keycloak.services.resources.admin.permissions.AdminPermissions;
|
||||||
import org.keycloak.testsuite.AbstractKeycloakTest;
|
import org.keycloak.testsuite.AbstractKeycloakTest;
|
||||||
import org.keycloak.testsuite.ProfileAssume;
|
import org.keycloak.testsuite.ProfileAssume;
|
||||||
|
import org.keycloak.testsuite.arquillian.annotation.UncaughtServerErrorExpected;
|
||||||
import org.keycloak.testsuite.auth.page.login.UpdateAccount;
|
import org.keycloak.testsuite.auth.page.login.UpdateAccount;
|
||||||
import org.keycloak.testsuite.pages.LoginPage;
|
import org.keycloak.testsuite.pages.LoginPage;
|
||||||
import org.keycloak.testsuite.pages.social.AbstractSocialLoginPage;
|
import org.keycloak.testsuite.pages.social.AbstractSocialLoginPage;
|
||||||
|
@ -235,6 +236,7 @@ public class SocialLoginTest extends AbstractKeycloakTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@UncaughtServerErrorExpected
|
||||||
public void googleLogin() throws InterruptedException {
|
public void googleLogin() throws InterruptedException {
|
||||||
setTestProvider(GOOGLE);
|
setTestProvider(GOOGLE);
|
||||||
performLogin();
|
performLogin();
|
||||||
|
@ -243,6 +245,7 @@ public class SocialLoginTest extends AbstractKeycloakTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@UncaughtServerErrorExpected
|
||||||
public void googleHostedDomainLogin() throws InterruptedException {
|
public void googleHostedDomainLogin() throws InterruptedException {
|
||||||
setTestProvider(GOOGLE_HOSTED_DOMAIN);
|
setTestProvider(GOOGLE_HOSTED_DOMAIN);
|
||||||
navigateToLoginPage();
|
navigateToLoginPage();
|
||||||
|
@ -269,6 +272,7 @@ public class SocialLoginTest extends AbstractKeycloakTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@UncaughtServerErrorExpected
|
||||||
public void bitbucketLogin() throws InterruptedException {
|
public void bitbucketLogin() throws InterruptedException {
|
||||||
setTestProvider(BITBUCKET);
|
setTestProvider(BITBUCKET);
|
||||||
performLogin();
|
performLogin();
|
||||||
|
@ -277,6 +281,7 @@ public class SocialLoginTest extends AbstractKeycloakTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@UncaughtServerErrorExpected
|
||||||
public void gitlabLogin() throws InterruptedException {
|
public void gitlabLogin() throws InterruptedException {
|
||||||
setTestProvider(GITLAB);
|
setTestProvider(GITLAB);
|
||||||
performLogin();
|
performLogin();
|
||||||
|
@ -285,6 +290,7 @@ public class SocialLoginTest extends AbstractKeycloakTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@UncaughtServerErrorExpected
|
||||||
public void facebookLogin() throws InterruptedException {
|
public void facebookLogin() throws InterruptedException {
|
||||||
setTestProvider(FACEBOOK);
|
setTestProvider(FACEBOOK);
|
||||||
performLogin();
|
performLogin();
|
||||||
|
@ -302,6 +308,7 @@ public class SocialLoginTest extends AbstractKeycloakTest {
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@UncaughtServerErrorExpected
|
||||||
public void githubLogin() throws InterruptedException {
|
public void githubLogin() throws InterruptedException {
|
||||||
setTestProvider(GITHUB);
|
setTestProvider(GITHUB);
|
||||||
performLogin();
|
performLogin();
|
||||||
|
@ -459,120 +466,137 @@ public class SocialLoginTest extends AbstractKeycloakTest {
|
||||||
updateAccountPage.submit();
|
updateAccountPage.submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void testTokenExchange() {
|
private WebTarget getExchangeUrl(Client httpClient) {
|
||||||
ProfileAssume.assumeFeatureEnabled(Profile.Feature.TOKEN_EXCHANGE);
|
return httpClient.target(OAuthClient.AUTH_SERVER_ROOT)
|
||||||
|
|
||||||
testingClient.server().run(SocialLoginTest::setupClientExchangePermissions);
|
|
||||||
|
|
||||||
List<UserRepresentation> users = adminClient.realm(REALM).users().search(null, null, null);
|
|
||||||
Assert.assertEquals(1, users.size());
|
|
||||||
String username = users.get(0).getUsername();
|
|
||||||
Client httpClient = ClientBuilder.newClient();
|
|
||||||
|
|
||||||
WebTarget exchangeUrl = httpClient.target(OAuthClient.AUTH_SERVER_ROOT)
|
|
||||||
.path("/realms")
|
.path("/realms")
|
||||||
.path(REALM)
|
.path(REALM)
|
||||||
.path("protocol/openid-connect/token");
|
.path("protocol/openid-connect/token");
|
||||||
|
|
||||||
// obtain social token
|
|
||||||
Response response = exchangeUrl.request()
|
|
||||||
.header(HttpHeaders.AUTHORIZATION, BasicAuthHelper.createHeader(EXCHANGE_CLIENT, "secret"))
|
|
||||||
.post(Entity.form(
|
|
||||||
new Form()
|
|
||||||
.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE)
|
|
||||||
.param(OAuth2Constants.REQUESTED_SUBJECT, username)
|
|
||||||
.param(OAuth2Constants.REQUESTED_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE)
|
|
||||||
.param(OAuth2Constants.REQUESTED_ISSUER, currentTestProvider.id())
|
|
||||||
|
|
||||||
));
|
|
||||||
Assert.assertEquals(200, response.getStatus());
|
|
||||||
AccessTokenResponse tokenResponse = response.readEntity(AccessTokenResponse.class);
|
|
||||||
response.close();
|
|
||||||
|
|
||||||
String socialToken = tokenResponse.getToken();
|
|
||||||
Assert.assertNotNull(socialToken);
|
|
||||||
|
|
||||||
// remove all users
|
|
||||||
removeUser();
|
|
||||||
|
|
||||||
users = adminClient.realm(REALM).users().search(null, null, null);
|
|
||||||
Assert.assertEquals(0, users.size());
|
|
||||||
|
|
||||||
// now try external exchange where we trust social provider and import the external token.
|
|
||||||
response = exchangeUrl.request()
|
|
||||||
.header(HttpHeaders.AUTHORIZATION, BasicAuthHelper.createHeader(EXCHANGE_CLIENT, "secret"))
|
|
||||||
.post(Entity.form(
|
|
||||||
new Form()
|
|
||||||
.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE)
|
|
||||||
.param(OAuth2Constants.SUBJECT_TOKEN, socialToken)
|
|
||||||
.param(OAuth2Constants.SUBJECT_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE)
|
|
||||||
.param(OAuth2Constants.SUBJECT_ISSUER, currentTestProvider.id())
|
|
||||||
|
|
||||||
));
|
|
||||||
Assert.assertEquals(200, response.getStatus());
|
|
||||||
tokenResponse = response.readEntity(AccessTokenResponse.class);
|
|
||||||
response.close();
|
|
||||||
|
|
||||||
users = adminClient.realm(REALM).users().search(null, null, null);
|
|
||||||
Assert.assertEquals(1, users.size());
|
|
||||||
|
|
||||||
Assert.assertEquals(username, users.get(0).getUsername());
|
|
||||||
|
|
||||||
// remove all users
|
|
||||||
removeUser();
|
|
||||||
|
|
||||||
users = adminClient.realm(REALM).users().search(null, null, null);
|
|
||||||
Assert.assertEquals(0, users.size());
|
|
||||||
|
|
||||||
///// Test that we can update social token from session with stored tokens turned off.
|
|
||||||
|
|
||||||
// turn off store token
|
|
||||||
IdentityProviderRepresentation idp = adminClient.realm(REALM).identityProviders().get(currentTestProvider.id).toRepresentation();
|
|
||||||
idp.setStoreToken(false);
|
|
||||||
adminClient.realm(REALM).identityProviders().get(idp.getAlias()).update(idp);
|
|
||||||
|
|
||||||
|
|
||||||
// first exchange social token to get a user session that should store the social token there
|
|
||||||
response = exchangeUrl.request()
|
|
||||||
.header(HttpHeaders.AUTHORIZATION, BasicAuthHelper.createHeader(EXCHANGE_CLIENT, "secret"))
|
|
||||||
.post(Entity.form(
|
|
||||||
new Form()
|
|
||||||
.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE)
|
|
||||||
.param(OAuth2Constants.SUBJECT_TOKEN, socialToken)
|
|
||||||
.param(OAuth2Constants.SUBJECT_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE)
|
|
||||||
.param(OAuth2Constants.SUBJECT_ISSUER, currentTestProvider.id())
|
|
||||||
|
|
||||||
));
|
|
||||||
Assert.assertEquals(200, response.getStatus());
|
|
||||||
tokenResponse = response.readEntity(AccessTokenResponse.class);
|
|
||||||
String keycloakToken = tokenResponse.getToken();
|
|
||||||
response.close();
|
|
||||||
|
|
||||||
// now take keycloak token and make sure it can get back the social token from the user session since stored tokens are off
|
|
||||||
response = exchangeUrl.request()
|
|
||||||
.header(HttpHeaders.AUTHORIZATION, BasicAuthHelper.createHeader(EXCHANGE_CLIENT, "secret"))
|
|
||||||
.post(Entity.form(
|
|
||||||
new Form()
|
|
||||||
.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE)
|
|
||||||
.param(OAuth2Constants.SUBJECT_TOKEN, keycloakToken)
|
|
||||||
.param(OAuth2Constants.SUBJECT_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE)
|
|
||||||
.param(OAuth2Constants.REQUESTED_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE)
|
|
||||||
.param(OAuth2Constants.REQUESTED_ISSUER, currentTestProvider.id())
|
|
||||||
|
|
||||||
));
|
|
||||||
Assert.assertEquals(200, response.getStatus());
|
|
||||||
tokenResponse = response.readEntity(AccessTokenResponse.class);
|
|
||||||
response.close();
|
|
||||||
|
|
||||||
Assert.assertEquals(socialToken, tokenResponse.getToken());
|
|
||||||
|
|
||||||
|
|
||||||
// turn on store token
|
|
||||||
idp = adminClient.realm(REALM).identityProviders().get(currentTestProvider.id).toRepresentation();
|
|
||||||
idp.setStoreToken(true);
|
|
||||||
adminClient.realm(REALM).identityProviders().get(idp.getAlias()).update(idp);
|
|
||||||
|
|
||||||
httpClient.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
private AccessTokenResponse checkFeature(int expectedStatusCode, String username) {
|
||||||
|
Client httpClient = ClientBuilder.newClient();
|
||||||
|
Response response = null;
|
||||||
|
try {
|
||||||
|
testingClient.server().run(SocialLoginTest::setupClientExchangePermissions);
|
||||||
|
|
||||||
|
WebTarget exchangeUrl = getExchangeUrl(httpClient);
|
||||||
|
response = exchangeUrl.request()
|
||||||
|
.header(HttpHeaders.AUTHORIZATION, BasicAuthHelper.createHeader(EXCHANGE_CLIENT, "secret"))
|
||||||
|
.post(Entity.form(
|
||||||
|
new Form()
|
||||||
|
.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE)
|
||||||
|
.param(OAuth2Constants.REQUESTED_SUBJECT, username)
|
||||||
|
.param(OAuth2Constants.REQUESTED_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE)
|
||||||
|
.param(OAuth2Constants.REQUESTED_ISSUER, currentTestProvider.id())
|
||||||
|
));
|
||||||
|
Assert.assertEquals(expectedStatusCode, response.getStatus());
|
||||||
|
if (expectedStatusCode == Response.Status.OK.getStatusCode())
|
||||||
|
return response.readEntity(AccessTokenResponse.class);
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
if (response != null)
|
||||||
|
response.close();
|
||||||
|
httpClient.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void testTokenExchange() {
|
||||||
|
List<UserRepresentation> users = adminClient.realm(REALM).users().search(null, null, null);
|
||||||
|
Assert.assertEquals(1, users.size());
|
||||||
|
|
||||||
|
String username = users.get(0).getUsername();
|
||||||
|
checkFeature(501, username);
|
||||||
|
|
||||||
|
Response tokenResp = testingClient.testing().enableFeature(Profile.Feature.TOKEN_EXCHANGE.toString());
|
||||||
|
assertEquals(200, tokenResp.getStatus());
|
||||||
|
|
||||||
|
ProfileAssume.assumeFeatureEnabled(Profile.Feature.TOKEN_EXCHANGE);
|
||||||
|
Client httpClient = ClientBuilder.newClient();
|
||||||
|
|
||||||
|
try {
|
||||||
|
AccessTokenResponse tokenResponse = checkFeature(200, username);
|
||||||
|
Assert.assertNotNull(tokenResponse);
|
||||||
|
String socialToken = tokenResponse.getToken();
|
||||||
|
Assert.assertNotNull(socialToken);
|
||||||
|
|
||||||
|
// remove all users
|
||||||
|
removeUser();
|
||||||
|
|
||||||
|
users = adminClient.realm(REALM).users().search(null, null, null);
|
||||||
|
Assert.assertEquals(0, users.size());
|
||||||
|
|
||||||
|
// now try external exchange where we trust social provider and import the external token.
|
||||||
|
Response response = getExchangeUrl(httpClient).request()
|
||||||
|
.header(HttpHeaders.AUTHORIZATION, BasicAuthHelper.createHeader(EXCHANGE_CLIENT, "secret"))
|
||||||
|
.post(Entity.form(
|
||||||
|
new Form()
|
||||||
|
.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE)
|
||||||
|
.param(OAuth2Constants.SUBJECT_TOKEN, socialToken)
|
||||||
|
.param(OAuth2Constants.SUBJECT_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE)
|
||||||
|
.param(OAuth2Constants.SUBJECT_ISSUER, currentTestProvider.id())
|
||||||
|
));
|
||||||
|
Assert.assertEquals(200, response.getStatus());
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
users = adminClient.realm(REALM).users().search(null, null, null);
|
||||||
|
Assert.assertEquals(1, users.size());
|
||||||
|
|
||||||
|
Assert.assertEquals(username, users.get(0).getUsername());
|
||||||
|
|
||||||
|
// remove all users
|
||||||
|
removeUser();
|
||||||
|
|
||||||
|
users = adminClient.realm(REALM).users().search(null, null, null);
|
||||||
|
Assert.assertEquals(0, users.size());
|
||||||
|
|
||||||
|
///// Test that we can update social token from session with stored tokens turned off.
|
||||||
|
|
||||||
|
// turn off store token
|
||||||
|
IdentityProviderRepresentation idp = adminClient.realm(REALM).identityProviders().get(currentTestProvider.id).toRepresentation();
|
||||||
|
idp.setStoreToken(false);
|
||||||
|
adminClient.realm(REALM).identityProviders().get(idp.getAlias()).update(idp);
|
||||||
|
|
||||||
|
// first exchange social token to get a user session that should store the social token there
|
||||||
|
response = getExchangeUrl(httpClient).request()
|
||||||
|
.header(HttpHeaders.AUTHORIZATION, BasicAuthHelper.createHeader(EXCHANGE_CLIENT, "secret"))
|
||||||
|
.post(Entity.form(
|
||||||
|
new Form()
|
||||||
|
.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE)
|
||||||
|
.param(OAuth2Constants.SUBJECT_TOKEN, socialToken)
|
||||||
|
.param(OAuth2Constants.SUBJECT_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE)
|
||||||
|
.param(OAuth2Constants.SUBJECT_ISSUER, currentTestProvider.id())
|
||||||
|
));
|
||||||
|
Assert.assertEquals(200, response.getStatus());
|
||||||
|
tokenResponse = response.readEntity(AccessTokenResponse.class);
|
||||||
|
String keycloakToken = tokenResponse.getToken();
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
// now take keycloak token and make sure it can get back the social token from the user session since stored tokens are off
|
||||||
|
response = getExchangeUrl(httpClient).request()
|
||||||
|
.header(HttpHeaders.AUTHORIZATION, BasicAuthHelper.createHeader(EXCHANGE_CLIENT, "secret"))
|
||||||
|
.post(Entity.form(
|
||||||
|
new Form()
|
||||||
|
.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE)
|
||||||
|
.param(OAuth2Constants.SUBJECT_TOKEN, keycloakToken)
|
||||||
|
.param(OAuth2Constants.SUBJECT_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE)
|
||||||
|
.param(OAuth2Constants.REQUESTED_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE)
|
||||||
|
.param(OAuth2Constants.REQUESTED_ISSUER, currentTestProvider.id())
|
||||||
|
));
|
||||||
|
Assert.assertEquals(200, response.getStatus());
|
||||||
|
tokenResponse = response.readEntity(AccessTokenResponse.class);
|
||||||
|
response.close();
|
||||||
|
|
||||||
|
Assert.assertEquals(socialToken, tokenResponse.getToken());
|
||||||
|
// turn on store token
|
||||||
|
idp = adminClient.realm(REALM).identityProviders().get(currentTestProvider.id).toRepresentation();
|
||||||
|
idp.setStoreToken(true);
|
||||||
|
adminClient.realm(REALM).identityProviders().get(idp.getAlias()).update(idp);
|
||||||
|
} finally {
|
||||||
|
httpClient.close();
|
||||||
|
tokenResp = testingClient.testing().disableFeature(Profile.Feature.TOKEN_EXCHANGE.toString());
|
||||||
|
assertEquals(200, tokenResp.getStatus());
|
||||||
|
checkFeature(501, username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue