Details
diff --git a/testsuite/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java b/testsuite/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
new file mode 100644
index 0000000..1617767
--- /dev/null
+++ b/testsuite/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
@@ -0,0 +1,92 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2012, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.keycloak.testsuite.oauth;
+
+import java.security.PublicKey;
+
+import org.apache.commons.io.IOUtils;
+import org.jboss.resteasy.security.PemUtils;
+import org.json.JSONObject;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.RSATokenVerifier;
+import org.keycloak.representations.SkeletonKeyToken;
+import org.keycloak.testsuite.OAuthClient;
+import org.keycloak.testsuite.OAuthClient.AccessTokenResponse;
+import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.rule.KeycloakRule;
+import org.keycloak.testsuite.rule.WebResource;
+import org.keycloak.testsuite.rule.WebRule;
+import org.openqa.selenium.WebDriver;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class AccessTokenTest {
+
+ @ClassRule
+ public static KeycloakRule keycloakRule = new KeycloakRule();
+
+ @Rule
+ public WebRule webRule = new WebRule(this);
+
+ @WebResource
+ protected WebDriver driver;
+
+ @WebResource
+ protected OAuthClient oauth;
+
+ @WebResource
+ protected LoginPage loginPage;
+
+ private PublicKey realmPublicKey;
+
+ @Before
+ public void before() throws Exception {
+ JSONObject realmJson = new JSONObject(IOUtils.toString(getClass().getResourceAsStream("/testrealm.json")));
+ realmPublicKey = PemUtils.decodePublicKey(realmJson.getString("publicKey"));
+ }
+
+ @Test
+ public void accessTokenRequest() throws Exception {
+ oauth.doLogin("test-user@localhost", "password");
+
+ String code = oauth.getCurrentQuery().get("code");
+ AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
+
+ Assert.assertEquals(200, response.getStatusCode());
+
+ Assert.assertTrue(response.getExpiresIn() <= 300 && response.getExpiresIn() >= 250);
+
+ Assert.assertEquals("bearer", response.getTokenType());
+
+ SkeletonKeyToken token = RSATokenVerifier.verifyToken(response.getAccessToken(), realmPublicKey, oauth.getRealm());
+ Assert.assertEquals("test-user@localhost", token.getPrincipal());
+
+ Assert.assertEquals(1, token.getRealmAccess().getRoles().size());
+ Assert.assertTrue(token.getRealmAccess().isUserInRole("user"));
+ }
+
+}
diff --git a/testsuite/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java b/testsuite/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
new file mode 100644
index 0000000..e6a89bd
--- /dev/null
+++ b/testsuite/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
@@ -0,0 +1,81 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2012, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.keycloak.testsuite.oauth;
+
+import java.io.IOException;
+
+import org.apache.http.client.ClientProtocolException;
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.testsuite.OAuthClient;
+import org.keycloak.testsuite.OAuthClient.AuthorizationCodeResponse;
+import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.rule.KeycloakRule;
+import org.keycloak.testsuite.rule.WebResource;
+import org.keycloak.testsuite.rule.WebRule;
+import org.openqa.selenium.WebDriver;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class AuthorizationCodeTest {
+
+ @ClassRule
+ public static KeycloakRule keycloakRule = new KeycloakRule();
+
+ @Rule
+ public WebRule webRule = new WebRule(this);
+
+ @WebResource
+ protected WebDriver driver;
+
+ @WebResource
+ protected OAuthClient oauth;
+
+ @WebResource
+ protected LoginPage loginPage;
+
+ @Test
+ public void authorizationRequest() throws ClientProtocolException, IOException {
+ oauth.state("mystate");
+
+ AuthorizationCodeResponse response = oauth.doLogin("test-user@localhost", "password");
+
+ Assert.assertTrue(response.isRedirected());
+ Assert.assertNotNull(response.getCode());
+ Assert.assertEquals("mystate", response.getState());
+ Assert.assertNull(response.getError());
+ }
+
+ @Test
+ public void authorizationRequestNoState() throws ClientProtocolException, IOException {
+ AuthorizationCodeResponse response = oauth.doLogin("test-user@localhost", "password");
+
+ Assert.assertTrue(response.isRedirected());
+ Assert.assertNotNull(response.getCode());
+ Assert.assertNull(response.getState());
+ Assert.assertNull(response.getError());
+ }
+
+}
diff --git a/testsuite/src/test/java/org/keycloak/testsuite/OAuthClient.java b/testsuite/src/test/java/org/keycloak/testsuite/OAuthClient.java
index bb1567a..42d2c32 100644
--- a/testsuite/src/test/java/org/keycloak/testsuite/OAuthClient.java
+++ b/testsuite/src/test/java/org/keycloak/testsuite/OAuthClient.java
@@ -23,14 +23,26 @@ package org.keycloak.testsuite;
import java.net.URI;
import java.net.URISyntaxException;
+import java.nio.charset.Charset;
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.ws.rs.core.UriBuilder;
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.message.BasicNameValuePair;
+import org.json.JSONObject;
+import org.junit.Assert;
+import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
/**
@@ -46,6 +58,8 @@ public class OAuthClient {
private String responseType = "code";
+ private String grantType = "authorization_code";
+
private String clientId = "test-app";
private String redirectUri = "http://localhost:8081/app/auth";
@@ -58,17 +72,42 @@ public class OAuthClient {
this.driver = driver;
}
- // public void login(String username, String password) throws UnsupportedEncodingException {
- // HttpClient client = new DefaultHttpClient();
- // HttpPost post = new HttpPost(getLoginFormUrl());
- //
- // List<NameValuePair> parameters = new LinkedList<NameValuePair>();
- // parameters.add(new BasicNameValuePair("username", username));
- // parameters.add(new BasicNameValuePair("password", password));
- //
- // UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters, Charset.forName("UTF-8"));
- // post.setEntity(formEntity);
- // }
+ public AuthorizationCodeResponse doLogin(String username, String password) {
+ openLoginForm();
+
+ driver.findElement(By.id("username")).sendKeys(username);
+ driver.findElement(By.id("password")).sendKeys(password);
+ driver.findElement(By.cssSelector("input[type=\"submit\"]")).click();
+
+ return new AuthorizationCodeResponse(this);
+ }
+
+ public AccessTokenResponse doAccessTokenRequest(String code, String password) throws Exception {
+ HttpClient client = new DefaultHttpClient();
+ HttpPost post = new HttpPost(getAccessTokenUrl());
+
+ List<NameValuePair> parameters = new LinkedList<NameValuePair>();
+ if (grantType != null) {
+ parameters.add(new BasicNameValuePair("grant_type", grantType));
+ }
+ if (code != null) {
+ parameters.add(new BasicNameValuePair("code", code));
+ }
+ if (redirectUri != null) {
+ parameters.add(new BasicNameValuePair("redirect_uri", redirectUri));
+ }
+ if (clientId != null) {
+ parameters.add(new BasicNameValuePair("client_id", clientId));
+ }
+ if (password != null) {
+ parameters.add(new BasicNameValuePair("password", password));
+ }
+
+ UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters, Charset.forName("UTF-8"));
+ post.setEntity(formEntity);
+
+ return new AccessTokenResponse(client.execute(post));
+ }
public boolean isAuthorizationResponse() {
return getCurrentRequest().equals(redirectUri) && getCurrentQuery().containsKey("code");
@@ -129,8 +168,12 @@ public class OAuthClient {
public String getLoginFormUrl() {
UriBuilder b = UriBuilder.fromUri(baseUrl + "/realms/" + realm + "/tokens/login");
- b.queryParam("response_type", responseType);
- b.queryParam("client_id", clientId);
+ if (responseType != null) {
+ b.queryParam("response_type", responseType);
+ }
+ if (clientId != null) {
+ b.queryParam("client_id", clientId);
+ }
if (redirectUri != null) {
b.queryParam("redirect_uri", redirectUri);
}
@@ -143,6 +186,11 @@ public class OAuthClient {
return b.build().toString();
}
+ public String getAccessTokenUrl() {
+ UriBuilder b = UriBuilder.fromUri(baseUrl + "/realms/" + realm + "/tokens/access/codes");
+ return b.build().toString();
+ }
+
public OAuthClient realm(String realm) {
this.realm = realm;
return this;
@@ -173,4 +221,96 @@ public class OAuthClient {
return this;
}
+ public String getRealm() {
+ return realm;
+ }
+
+ public static class AuthorizationCodeResponse {
+
+ private boolean isRedirected;
+ private String code;
+ private String state;
+ private String error;
+
+ public AuthorizationCodeResponse(OAuthClient client) {
+ isRedirected = client.getCurrentRequest().equals(client.getRedirectUri());
+ code = client.getCurrentQuery().get("code");
+ state = client.getCurrentQuery().get("state");
+ error = client.getCurrentQuery().get("error");
+ }
+
+ public boolean isRedirected() {
+ return isRedirected;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public String getState() {
+ return state;
+ }
+
+ public String getError() {
+ return error;
+ }
+
+ }
+
+ public static class AccessTokenResponse {
+ private int statusCode;
+
+ private String accessToken;
+ private String tokenType;
+ private int expiresIn;
+ private String refreshToken;
+
+ private String error;
+
+ public AccessTokenResponse(HttpResponse response) throws Exception {
+ statusCode = response.getStatusLine().getStatusCode();
+ if (!"application/json".equals(response.getHeaders("Content-Type")[0].getValue())) {
+ Assert.fail("Invalid content type");
+ }
+
+ JSONObject responseJson = new JSONObject(IOUtils.toString(response.getEntity().getContent()));
+
+ if (statusCode == 200) {
+ accessToken = responseJson.getString("access_token");
+ tokenType = responseJson.getString("token_type");
+ expiresIn = responseJson.getInt("expires_in");
+
+ if (responseJson.has("refresh_token")) {
+ refreshToken = responseJson.getString("refresh_token");
+ }
+ } else {
+ error = responseJson.getString("error");
+ }
+ }
+
+ public String getAccessToken() {
+ return accessToken;
+ }
+
+ public String getError() {
+ return error;
+ }
+
+ public int getExpiresIn() {
+ return expiresIn;
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public String getRefreshToken() {
+ return refreshToken;
+ }
+
+ public String getTokenType() {
+ return tokenType;
+ }
+ }
+
}