Added some basic oauth tests
This commit is contained in:
parent
09304ac2ef
commit
811493f61a
3 changed files with 326 additions and 13 deletions
|
@ -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");
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue