keycloak-aplcache

Details

diff --git a/testsuite/integration-arquillian/HOW-TO-RUN.md b/testsuite/integration-arquillian/HOW-TO-RUN.md
index 84365ef..b11455b 100644
--- a/testsuite/integration-arquillian/HOW-TO-RUN.md
+++ b/testsuite/integration-arquillian/HOW-TO-RUN.md
@@ -159,5 +159,52 @@ mvn -f testsuite/integration-arquillian/pom.xml \
 ````
 
 
+## Social Login
+The social login tests require setup of all social networks including an example social user. These details can't be 
+shared as it would result in the clients and users eventually being blocked. By default these tests are skipped.
+   
+To run the full test you need to configure clients in Google, Facebook, GitHub, Twitter, LinkedIn, Microsoft and 
+StackOverflow. See the server administration guide for details on how to do that. Further, you also need to create a 
+sample user that can login to the social network.
+ 
+The details should be added to a standard properties file. For some properties you can use shared common properties and
+override when needed. Or you can specify these for all providers. All providers require at least clientId and 
+clientSecret (StackOverflow also requires clientKey).
+ 
+An example social.properties file looks like:
+
+    common.username=sampleuser@example.org
+    common.password=commonpassword
+    common.profile.firstName=Foo
+    common.profile.lastName=Bar
+    common.profile.email=sampleuser@example.org
+
+    google.clientId=asdfasdfasdfasdfsadf
+    google.clientSecret=zxcvzxcvzxcvzxcv
+
+    facebook.clientId=asdfasdfasdfasdfsadf
+    facebook.clientSecret=zxcvzxcvzxcvzxcv
+    facebook.profile.lastName=Test
+
+In the example above the common username, password and profile are shared for all providers, but Facebook has a 
+different last name.
 
+Some providers actively block bots so you need to use a proper browser to test. Either Firefox or Chrome should work.
 
+To run the tests run:
+
+    mvn -f testsuite/integration-arquillian/pom.xml \
+          clean install \
+          -Pauth-server-wildfly \
+          -Dtest=SocialLoginTest \
+          -Dbrowser=chrome \
+          -Dsocial.config=/path/to/social.properties
+
+
+## Different Browsers
+ 
+To run with Chrome add `-Dbrowser=chrome`. Depending on the Chrome version you have you may need to download the latest
+chromedriver from https://sites.google.com/a/chromium.org/chromedriver/downloads and point to it with 
+`-Dwebdriver.chrome.driver=/path/to/chromedriver`.
+ 
+    
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/keystore/keycloak.truststore b/testsuite/integration-arquillian/servers/auth-server/jboss/common/keystore/keycloak.truststore
index 2df5170..da0f709 100644
Binary files a/testsuite/integration-arquillian/servers/auth-server/jboss/common/keystore/keycloak.truststore and b/testsuite/integration-arquillian/servers/auth-server/jboss/common/keystore/keycloak.truststore differ
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java
index 9748a9f..2a3f944 100755
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/AccountUpdateProfilePage.java
@@ -63,6 +63,10 @@ public class AccountUpdateProfilePage extends AbstractAccountPage {
         return RealmsResource.accountUrl(UriBuilder.fromUri(getAuthServerRoot())).build("test").toString();
     }
 
+    public String getPath(String realm) {
+        return RealmsResource.accountUrl(UriBuilder.fromUri(getAuthServerRoot())).build(realm).toString();
+    }
+
     public void updateProfile(String firstName, String lastName, String email) {
         firstNameInput.clear();
         firstNameInput.sendKeys(firstName);
@@ -141,6 +145,10 @@ public class AccountUpdateProfilePage extends AbstractAccountPage {
         driver.navigate().to(getPath());
     }
 
+    public void open(String realm) {
+        driver.navigate().to(getPath(realm));
+    }
+
     public void backToApplication() {
         backToApplicationLink.click();
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/LoginUpdateProfilePage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/LoginUpdateProfilePage.java
index 704060b..239cfb9 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/LoginUpdateProfilePage.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/LoginUpdateProfilePage.java
@@ -41,12 +41,18 @@ public class LoginUpdateProfilePage extends AbstractPage {
     private WebElement loginErrorMessage;
 
     public void update(String firstName, String lastName, String email) {
-        firstNameInput.clear();
-        firstNameInput.sendKeys(firstName);
-        lastNameInput.clear();
-        lastNameInput.sendKeys(lastName);
-        emailInput.clear();
-        emailInput.sendKeys(email);
+        if (firstName != null) {
+            firstNameInput.clear();
+            firstNameInput.sendKeys(firstName);
+        }
+        if (lastName != null) {
+            lastNameInput.clear();
+            lastNameInput.sendKeys(lastName);
+        }
+        if (email != null) {
+            emailInput.clear();
+            emailInput.sendKeys(email);
+        }
         submitButton.click();
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/SocialLoginTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/SocialLoginTest.java
new file mode 100644
index 0000000..6ac3970
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/SocialLoginTest.java
@@ -0,0 +1,232 @@
+package org.keycloak.testsuite.broker;
+
+import org.jboss.arquillian.graphene.Graphene;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.arquillian.graphene.wait.WebDriverWait;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.keycloak.common.Profile;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.AbstractKeycloakTest;
+import org.keycloak.testsuite.cli.exec.ExecutionException;
+import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
+import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.pages.LoginUpdateProfilePage;
+import org.keycloak.testsuite.util.IdentityProviderBuilder;
+import org.keycloak.testsuite.util.RealmBuilder;
+import org.openqa.selenium.By;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+
+import java.io.FileInputStream;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+/**
+ * Created by st on 19.01.17.
+ */
+public class SocialLoginTest extends AbstractKeycloakTest {
+
+    public static final String SOCIAL_CONFIG = "social.config";
+
+    private static Properties config = new Properties();
+
+    @Page
+    public AccountUpdateProfilePage account;
+
+    @Page
+    public LoginPage loginPage;
+
+    @Page
+    public LoginUpdateProfilePage updateProfilePage;
+
+    @BeforeClass
+    public static void loadConfig() throws Exception {
+        assumeTrue(System.getProperties().containsKey(SOCIAL_CONFIG));
+
+        config.load(new FileInputStream(System.getProperty(SOCIAL_CONFIG)));
+    }
+
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+        RealmRepresentation rep = RealmBuilder.create().name("social").build();
+        List<IdentityProviderRepresentation> idps = new LinkedList<>();
+        rep.setIdentityProviders(idps);
+
+        idps.add(buildIdp("google"));
+        idps.add(buildIdp("facebook"));
+        idps.add(buildIdp("github"));
+        idps.add(buildIdp("twitter"));
+        idps.add(buildIdp("linkedin"));
+        idps.add(buildIdp("microsoft"));
+        idps.add(buildIdp("stackoverflow"));
+
+        testRealms.add(rep);
+    }
+
+    @Test
+    public void googleLogin() throws InterruptedException {
+        account.open("social");
+
+        loginPage.clickSocial("google");
+
+        Graphene.waitGui().until(ExpectedConditions.visibilityOfElementLocated(By.id("Email")));
+
+        driver.findElement(By.id("Email")).sendKeys(config.getProperty("google.username", config.getProperty("common.username")));
+        driver.findElement(By.id("next")).click();
+
+        Graphene.waitGui().until(ExpectedConditions.visibilityOfElementLocated(By.id("Passwd")));
+
+        driver.findElement(By.id("Passwd")).sendKeys(config.getProperty("google.password", config.getProperty("common.password")));
+        driver.findElement(By.id("signIn")).click();
+
+        Graphene.waitGui().until(ExpectedConditions.elementToBeClickable(By.id("submit_approve_access")));
+
+        driver.findElement(By.id("submit_approve_access")).click();
+
+        assertEquals(config.getProperty("google.profile.firstName", config.getProperty("common.profile.firstName")), account.getFirstName());
+        assertEquals(config.getProperty("google.profile.lastName", config.getProperty("common.profile.lastName")), account.getLastName());
+        assertEquals(config.getProperty("google.profile.email", config.getProperty("common.profile.email")), account.getEmail());
+    }
+
+    @Test
+    public void faceBookLogin() {
+        account.open("social");
+
+        loginPage.clickSocial("facebook");
+
+        Graphene.waitGui().until(ExpectedConditions.visibilityOfElementLocated(By.id("email")));
+        driver.findElement(By.id("email")).sendKeys(config.getProperty("facebook.username", config.getProperty("common.username")));
+        driver.findElement(By.id("pass")).sendKeys(config.getProperty("facebook.password", config.getProperty("common.password")));
+
+        driver.findElement(By.id("loginbutton")).click();
+
+        assertEquals(config.getProperty("facebook.profile.firstName", config.getProperty("common.profile.firstName")), account.getFirstName());
+        assertEquals(config.getProperty("facebook.profile.lastName", config.getProperty("common.profile.lastName")), account.getLastName());
+        assertEquals(config.getProperty("facebook.profile.email", config.getProperty("common.profile.email")), account.getEmail());
+    }
+
+    @Test
+    public void githubLogin() {
+        account.open("social");
+
+        loginPage.clickSocial("github");
+
+        Graphene.waitGui().until(ExpectedConditions.visibilityOfElementLocated(By.id("login_field")));
+        driver.findElement(By.id("login_field")).sendKeys(config.getProperty("github.username", config.getProperty("common.username")));
+        driver.findElement(By.id("password")).sendKeys(config.getProperty("github.password", config.getProperty("common.password")));
+
+        driver.findElement(By.name("commit")).click();
+
+        assertEquals(config.getProperty("github.profile.firstName", config.getProperty("common.profile.firstName")), account.getFirstName());
+        assertEquals(config.getProperty("github.profile.lastName", config.getProperty("common.profile.lastName")), account.getLastName());
+        assertEquals(config.getProperty("github.profile.email", config.getProperty("common.profile.email")), account.getEmail());
+    }
+
+    @Test
+    public void twitterLogin() {
+        account.open("social");
+
+        loginPage.clickSocial("twitter");
+
+        Graphene.waitGui().until(ExpectedConditions.visibilityOfElementLocated(By.id("username_or_email")));
+        driver.findElement(By.id("username_or_email")).sendKeys(config.getProperty("twitter.username", config.getProperty("common.username")));
+        driver.findElement(By.id("password")).sendKeys(config.getProperty("twitter.password", config.getProperty("common.password")));
+
+        driver.findElement(By.id("allow")).click();
+
+        assertTrue(updateProfilePage.isCurrent());
+
+        assertEquals(config.getProperty("twitter.profile.firstName", config.getProperty("common.profile.firstName")), account.getFirstName());
+        assertEquals(config.getProperty("twitter.profile.lastName", config.getProperty("common.profile.lastName")), account.getLastName());
+        assertEquals("", updateProfilePage.getEmail());
+
+        updateProfilePage.update(null, null, "keycloakey@gmail.com");
+
+        assertEquals(config.getProperty("twitter.profile.firstName", config.getProperty("common.profile.firstName")), account.getFirstName());
+        assertEquals(config.getProperty("twitter.profile.lastName", config.getProperty("common.profile.lastName")), account.getLastName());
+        assertEquals(config.getProperty("twitter.profile.email", config.getProperty("common.profile.email")), account.getEmail());
+    }
+
+    @Test
+    public void linkedinLogin() {
+        account.open("social");
+
+        loginPage.clickSocial("linkedin");
+
+        Graphene.waitGui().until(ExpectedConditions.visibilityOfElementLocated(By.id("session_key-oauth2SAuthorizeForm")));
+        driver.findElement(By.id("session_key-oauth2SAuthorizeForm")).sendKeys(config.getProperty("linkedin.username", config.getProperty("common.username")));
+        driver.findElement(By.id("session_password-oauth2SAuthorizeForm")).sendKeys(config.getProperty("linkedin.password", config.getProperty("common.password")));
+
+        driver.findElement(By.name("authorize")).click();
+
+        assertEquals(config.getProperty("linkedin.profile.firstName", config.getProperty("common.profile.firstName")), account.getFirstName());
+        assertEquals(config.getProperty("linkedin.profile.lastName", config.getProperty("common.profile.lastName")), account.getLastName());
+        assertEquals(config.getProperty("linkedin.profile.email", config.getProperty("common.profile.email")), account.getEmail());
+    }
+
+    @Test
+    public void microsoftLogin() {
+        account.open("social");
+
+        loginPage.clickSocial("microsoft");
+
+        Graphene.waitGui().until(ExpectedConditions.visibilityOfElementLocated(By.name("loginfmt")));
+        driver.findElement(By.name("loginfmt")).sendKeys(config.getProperty("microsoft.username", config.getProperty("common.username")));
+        driver.findElement(By.xpath("//input[@value='Next']")).click();
+
+        Graphene.waitGui().until(ExpectedConditions.visibilityOfElementLocated(By.name("passwd")));
+        driver.findElement(By.name("passwd")).sendKeys(config.getProperty("microsoft.password", config.getProperty("common.password")));
+        driver.findElement(By.xpath("//input[@value='Sign in']")).click();
+
+        assertEquals(config.getProperty("microsoft.profile.firstName", config.getProperty("common.profile.firstName")), account.getFirstName());
+        assertEquals(config.getProperty("microsoft.profile.lastName", config.getProperty("common.profile.lastName")), account.getLastName());
+        assertEquals(config.getProperty("microsoft.profile.email", config.getProperty("common.profile.email")), account.getEmail());
+    }
+
+    @Test
+    public void stackoverflowLogin() {
+        account.open("social");
+
+        loginPage.clickSocial("stackoverflow");
+
+        Graphene.waitModel().until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//a[@title='log in with Stack_Exchange']")));
+        driver.findElement(By.xpath("//a[@title='log in with Stack_Exchange']")).click();
+
+        driver.switchTo().frame(driver.findElement(By.id("affiliate-signin-iframe")));
+
+        Graphene.waitGui().until(ExpectedConditions.visibilityOfElementLocated(By.name("email")));
+        driver.findElement(By.name("email")).sendKeys(config.getProperty("stackoverflow.username", config.getProperty("common.username")));
+        driver.findElement(By.name("password")).sendKeys(config.getProperty("stackoverflow.password", config.getProperty("common.password")));
+
+        driver.findElement(By.xpath("//input[@value='Sign In']")).click();
+
+        assertEquals(config.getProperty("stackoverflow.profile.firstName", config.getProperty("common.profile.firstName")), updateProfilePage.getFirstName());
+        assertEquals(config.getProperty("stackoverflow.profile.lastName", config.getProperty("common.profile.lastName")), updateProfilePage.getLastName());
+        assertEquals("", updateProfilePage.getEmail());
+
+        updateProfilePage.update(null, null, "keycloakey@gmail.com");
+
+        assertEquals(config.getProperty("stackoverflow.profile.firstName", config.getProperty("common.profile.firstName")), account.getFirstName());
+        assertEquals(config.getProperty("stackoverflow.profile.lastName", config.getProperty("common.profile.lastName")), account.getLastName());
+        assertEquals(config.getProperty("stackoverflow.profile.email", config.getProperty("common.profile.email")), account.getEmail());
+    }
+
+    private IdentityProviderRepresentation buildIdp(String id) {
+        IdentityProviderRepresentation idp = IdentityProviderBuilder.create().alias(id).providerId(id).build();
+        idp.setEnabled(true);
+        idp.getConfig().put("clientId", config.getProperty(id + ".clientId"));
+        idp.getConfig().put("clientSecret", config.getProperty(id + ".clientSecret"));
+        if (id.equals("stackoverflow")) {
+            idp.getConfig().put("key", config.getProperty(id + ".clientKey"));
+        }
+        return idp;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/keystore/keycloak.truststore b/testsuite/integration-arquillian/tests/base/src/test/resources/keystore/keycloak.truststore
index 2df5170..da0f709 100644
Binary files a/testsuite/integration-arquillian/tests/base/src/test/resources/keystore/keycloak.truststore and b/testsuite/integration-arquillian/tests/base/src/test/resources/keystore/keycloak.truststore differ