KEYCLOAK-547
This commit is contained in:
parent
c17a5823e9
commit
32a19563a5
3 changed files with 374 additions and 325 deletions
|
@ -429,6 +429,14 @@ public class TokenService {
|
|||
|
||||
ClientModel client = authorizeClient(authorizationHeader, form, audit);
|
||||
String refreshToken = form.getFirst(OAuth2Constants.REFRESH_TOKEN);
|
||||
if (refreshToken == null) {
|
||||
Map<String, String> error = new HashMap<String, String>();
|
||||
error.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_REQUEST);
|
||||
error.put(OAuth2Constants.ERROR_DESCRIPTION, "No refresh token");
|
||||
audit.error(Errors.INVALID_TOKEN);
|
||||
logger.error("OAuth Error: no refresh token");
|
||||
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
|
||||
}
|
||||
AccessToken accessToken;
|
||||
try {
|
||||
accessToken = tokenManager.refreshAccessToken(session, uriInfo, clientConnection, realm, client, refreshToken, audit);
|
||||
|
|
|
@ -1,325 +1,325 @@
|
|||
/*
|
||||
* 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 org.junit.Assert;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.audit.Details;
|
||||
import org.keycloak.audit.Errors;
|
||||
import org.keycloak.audit.Event;
|
||||
import org.keycloak.audit.EventType;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.resources.TokenService;
|
||||
import org.keycloak.testsuite.AssertEvents;
|
||||
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.keycloak.util.BasicAuthHelper;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
import javax.ws.rs.client.Client;
|
||||
import javax.ws.rs.client.ClientBuilder;
|
||||
import javax.ws.rs.client.Entity;
|
||||
import javax.ws.rs.client.WebTarget;
|
||||
import javax.ws.rs.core.Form;
|
||||
import javax.ws.rs.core.GenericType;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||
import static org.hamcrest.Matchers.lessThanOrEqualTo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
@Rule
|
||||
public AssertEvents events = new AssertEvents(keycloakRule);
|
||||
|
||||
@Test
|
||||
public void accessTokenRequest() throws Exception {
|
||||
oauth.doLogin("test-user@localhost", "password");
|
||||
|
||||
Event loginEvent = events.expectLogin().assertEvent();
|
||||
|
||||
String sessionId = loginEvent.getSessionId();
|
||||
String codeId = loginEvent.getDetails().get(Details.CODE_ID);
|
||||
|
||||
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||
AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
|
||||
|
||||
Assert.assertEquals(200, response.getStatusCode());
|
||||
|
||||
Assert.assertThat(response.getExpiresIn(), allOf(greaterThanOrEqualTo(250), lessThanOrEqualTo(300)));
|
||||
|
||||
Assert.assertEquals("bearer", response.getTokenType());
|
||||
|
||||
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
||||
|
||||
Assert.assertEquals(keycloakRule.getUser("test", "test-user@localhost").getId(), token.getSubject());
|
||||
Assert.assertNotEquals("test-user@localhost", token.getSubject());
|
||||
|
||||
Assert.assertEquals(sessionId, token.getSessionState());
|
||||
|
||||
Assert.assertEquals(1, token.getRealmAccess().getRoles().size());
|
||||
Assert.assertTrue(token.getRealmAccess().isUserInRole("user"));
|
||||
|
||||
Assert.assertEquals(1, token.getResourceAccess(oauth.getClientId()).getRoles().size());
|
||||
Assert.assertTrue(token.getResourceAccess(oauth.getClientId()).isUserInRole("customer-user"));
|
||||
|
||||
Event event = events.expectCodeToToken(codeId, sessionId).assertEvent();
|
||||
Assert.assertEquals(token.getId(), event.getDetails().get(Details.TOKEN_ID));
|
||||
Assert.assertEquals(oauth.verifyRefreshToken(response.getRefreshToken()).getId(), event.getDetails().get(Details.REFRESH_TOKEN_ID));
|
||||
Assert.assertEquals(sessionId, token.getSessionState());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessTokenInvalidClientCredentials() throws Exception {
|
||||
oauth.doLogin("test-user@localhost", "password");
|
||||
|
||||
Event loginEvent = events.expectLogin().assertEvent();
|
||||
String codeId = loginEvent.getDetails().get(Details.CODE_ID);
|
||||
|
||||
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||
AccessTokenResponse response = oauth.doAccessTokenRequest(code, "invalid");
|
||||
Assert.assertEquals(400, response.getStatusCode());
|
||||
|
||||
events.expectCodeToToken(codeId, loginEvent.getSessionId()).error("invalid_client_credentials").removeDetail(Details.TOKEN_ID).removeDetail(Details.REFRESH_TOKEN_ID).assertEvent();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessTokenUserSessionExpired() {
|
||||
oauth.doLogin("test-user@localhost", "password");
|
||||
|
||||
Event loginEvent = events.expectLogin().assertEvent();
|
||||
|
||||
String codeId = loginEvent.getDetails().get(Details.CODE_ID);
|
||||
String sessionId = loginEvent.getSessionId();
|
||||
|
||||
keycloakRule.removeUserSession(sessionId);
|
||||
|
||||
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||
|
||||
OAuthClient.AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(code, "password");
|
||||
assertEquals(400, tokenResponse.getStatusCode());
|
||||
assertNull(tokenResponse.getAccessToken());
|
||||
assertNull(tokenResponse.getRefreshToken());
|
||||
|
||||
events.expectCodeToToken(codeId, sessionId).removeDetail(Details.TOKEN_ID).client((String) null).user((String) null).session((String) null).removeDetail(Details.REFRESH_TOKEN_ID).error(Errors.INVALID_CODE).assertEvent();
|
||||
|
||||
events.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessTokenCodeExpired() {
|
||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
appRealm.setAccessCodeLifespan(1);
|
||||
}
|
||||
});
|
||||
|
||||
oauth.doLogin("test-user@localhost", "password");
|
||||
|
||||
Event loginEvent = events.expectLogin().assertEvent();
|
||||
|
||||
String codeId = loginEvent.getDetails().get(Details.CODE_ID);
|
||||
loginEvent.getSessionId();
|
||||
|
||||
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
|
||||
OAuthClient.AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
|
||||
Assert.assertEquals(400, response.getStatusCode());
|
||||
|
||||
AssertEvents.ExpectedEvent expectedEvent = events.expectCodeToToken(codeId, null);
|
||||
expectedEvent.error("invalid_code").removeDetail(Details.TOKEN_ID).removeDetail(Details.REFRESH_TOKEN_ID).client((String) null).user((String) null);
|
||||
expectedEvent.assertEvent();
|
||||
|
||||
events.clear();
|
||||
|
||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
appRealm.setAccessCodeLifespan(60);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessTokenCodeUsed() {
|
||||
oauth.doLogin("test-user@localhost", "password");
|
||||
|
||||
Event loginEvent = events.expectLogin().assertEvent();
|
||||
|
||||
String codeId = loginEvent.getDetails().get(Details.CODE_ID);
|
||||
loginEvent.getSessionId();
|
||||
|
||||
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||
OAuthClient.AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
|
||||
Assert.assertEquals(200, response.getStatusCode());
|
||||
|
||||
events.clear();
|
||||
|
||||
response = oauth.doAccessTokenRequest(code, "password");
|
||||
Assert.assertEquals(400, response.getStatusCode());
|
||||
|
||||
AssertEvents.ExpectedEvent expectedEvent = events.expectCodeToToken(codeId, null);
|
||||
expectedEvent.error("invalid_code").removeDetail(Details.TOKEN_ID).removeDetail(Details.REFRESH_TOKEN_ID).client((String) null).user((String) null);
|
||||
expectedEvent.assertEvent();
|
||||
|
||||
events.clear();
|
||||
|
||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
appRealm.setAccessCodeLifespan(60);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessTokenCodeHasRequiredAction() {
|
||||
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel defaultRealm, RealmModel appRealm) {
|
||||
UserModel user = manager.getSession().users().getUserByUsername("test-user@localhost", appRealm);
|
||||
user.addRequiredAction(UserModel.RequiredAction.UPDATE_PROFILE);
|
||||
}
|
||||
});
|
||||
|
||||
oauth.doLogin("test-user@localhost", "password");
|
||||
|
||||
String code = driver.getPageSource().split("code=")[1].split("&")[0].split("\"")[0];
|
||||
|
||||
OAuthClient.AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
|
||||
Assert.assertEquals(400, response.getStatusCode());
|
||||
|
||||
Event event = events.poll();
|
||||
assertNotNull(event.getDetails().get(Details.CODE_ID));
|
||||
|
||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
manager.getSession().users().getUserByUsername("test-user@localhost", appRealm).removeRequiredAction(UserModel.RequiredAction.UPDATE_PROFILE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateAccessToken() throws Exception {
|
||||
Client client = ClientBuilder.newClient();
|
||||
UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
|
||||
URI grantUri = TokenService.grantAccessTokenUrl(builder).build("test");
|
||||
WebTarget grantTarget = client.target(grantUri);
|
||||
builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
|
||||
URI validateUri = TokenService.validateAccessTokenUrl(builder).build("test");
|
||||
WebTarget validateTarget = client.target(validateUri);
|
||||
|
||||
{
|
||||
Response response = validateTarget.queryParam("access_token", "bad token").request().get();
|
||||
Assert.assertEquals(400, response.getStatus());
|
||||
HashMap<String, String> error = response.readEntity(new GenericType <HashMap<String, String>>() {});
|
||||
Assert.assertNotNull(error.get("error"));
|
||||
}
|
||||
|
||||
|
||||
org.keycloak.representations.AccessTokenResponse tokenResponse = null;
|
||||
{
|
||||
String header = BasicAuthHelper.createHeader("test-app", "password");
|
||||
Form form = new Form();
|
||||
form.param("username", "test-user@localhost")
|
||||
.param("password", "password");
|
||||
Response response = grantTarget.request()
|
||||
.header(HttpHeaders.AUTHORIZATION, header)
|
||||
.post(Entity.form(form));
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
|
||||
response.close();
|
||||
}
|
||||
|
||||
{
|
||||
Response response = validateTarget.queryParam("access_token", tokenResponse.getToken()).request().get();
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
AccessToken token = response.readEntity(AccessToken.class);
|
||||
Assert.assertNotNull(token);
|
||||
response.close();
|
||||
}
|
||||
{
|
||||
builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
|
||||
URI logoutUri = TokenService.logoutUrl(builder).build("test");
|
||||
Response response = client.target(logoutUri).queryParam("session_state", tokenResponse.getSessionState()).request().get();
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
response.close();
|
||||
}
|
||||
{
|
||||
Response response = validateTarget.queryParam("access_token", tokenResponse.getToken()).request().get();
|
||||
Assert.assertEquals(400, response.getStatus());
|
||||
HashMap<String, String> error = response.readEntity(new GenericType <HashMap<String, String>>() {});
|
||||
Assert.assertNotNull(error.get("error"));
|
||||
}
|
||||
|
||||
client.close();
|
||||
events.clear();
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
/*
|
||||
* 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 org.junit.Assert;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.audit.Details;
|
||||
import org.keycloak.audit.Errors;
|
||||
import org.keycloak.audit.Event;
|
||||
import org.keycloak.audit.EventType;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.resources.TokenService;
|
||||
import org.keycloak.testsuite.AssertEvents;
|
||||
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.keycloak.util.BasicAuthHelper;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
import javax.ws.rs.client.Client;
|
||||
import javax.ws.rs.client.ClientBuilder;
|
||||
import javax.ws.rs.client.Entity;
|
||||
import javax.ws.rs.client.WebTarget;
|
||||
import javax.ws.rs.core.Form;
|
||||
import javax.ws.rs.core.GenericType;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||
import static org.hamcrest.Matchers.lessThanOrEqualTo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
@Rule
|
||||
public AssertEvents events = new AssertEvents(keycloakRule);
|
||||
|
||||
@Test
|
||||
public void accessTokenRequest() throws Exception {
|
||||
oauth.doLogin("test-user@localhost", "password");
|
||||
|
||||
Event loginEvent = events.expectLogin().assertEvent();
|
||||
|
||||
String sessionId = loginEvent.getSessionId();
|
||||
String codeId = loginEvent.getDetails().get(Details.CODE_ID);
|
||||
|
||||
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||
AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
|
||||
|
||||
Assert.assertEquals(200, response.getStatusCode());
|
||||
|
||||
Assert.assertThat(response.getExpiresIn(), allOf(greaterThanOrEqualTo(250), lessThanOrEqualTo(300)));
|
||||
|
||||
Assert.assertEquals("bearer", response.getTokenType());
|
||||
|
||||
AccessToken token = oauth.verifyToken(response.getAccessToken());
|
||||
|
||||
Assert.assertEquals(keycloakRule.getUser("test", "test-user@localhost").getId(), token.getSubject());
|
||||
Assert.assertNotEquals("test-user@localhost", token.getSubject());
|
||||
|
||||
Assert.assertEquals(sessionId, token.getSessionState());
|
||||
|
||||
Assert.assertEquals(1, token.getRealmAccess().getRoles().size());
|
||||
Assert.assertTrue(token.getRealmAccess().isUserInRole("user"));
|
||||
|
||||
Assert.assertEquals(1, token.getResourceAccess(oauth.getClientId()).getRoles().size());
|
||||
Assert.assertTrue(token.getResourceAccess(oauth.getClientId()).isUserInRole("customer-user"));
|
||||
|
||||
Event event = events.expectCodeToToken(codeId, sessionId).assertEvent();
|
||||
Assert.assertEquals(token.getId(), event.getDetails().get(Details.TOKEN_ID));
|
||||
Assert.assertEquals(oauth.verifyRefreshToken(response.getRefreshToken()).getId(), event.getDetails().get(Details.REFRESH_TOKEN_ID));
|
||||
Assert.assertEquals(sessionId, token.getSessionState());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessTokenInvalidClientCredentials() throws Exception {
|
||||
oauth.doLogin("test-user@localhost", "password");
|
||||
|
||||
Event loginEvent = events.expectLogin().assertEvent();
|
||||
String codeId = loginEvent.getDetails().get(Details.CODE_ID);
|
||||
|
||||
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||
AccessTokenResponse response = oauth.doAccessTokenRequest(code, "invalid");
|
||||
Assert.assertEquals(400, response.getStatusCode());
|
||||
|
||||
events.expectCodeToToken(codeId, loginEvent.getSessionId()).error("invalid_client_credentials").removeDetail(Details.TOKEN_ID).removeDetail(Details.REFRESH_TOKEN_ID).assertEvent();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessTokenUserSessionExpired() {
|
||||
oauth.doLogin("test-user@localhost", "password");
|
||||
|
||||
Event loginEvent = events.expectLogin().assertEvent();
|
||||
|
||||
String codeId = loginEvent.getDetails().get(Details.CODE_ID);
|
||||
String sessionId = loginEvent.getSessionId();
|
||||
|
||||
keycloakRule.removeUserSession(sessionId);
|
||||
|
||||
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||
|
||||
OAuthClient.AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(code, "password");
|
||||
assertEquals(400, tokenResponse.getStatusCode());
|
||||
assertNull(tokenResponse.getAccessToken());
|
||||
assertNull(tokenResponse.getRefreshToken());
|
||||
|
||||
events.expectCodeToToken(codeId, sessionId).removeDetail(Details.TOKEN_ID).client((String) null).user((String) null).session((String) null).removeDetail(Details.REFRESH_TOKEN_ID).error(Errors.INVALID_CODE).assertEvent();
|
||||
|
||||
events.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessTokenCodeExpired() {
|
||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
appRealm.setAccessCodeLifespan(1);
|
||||
}
|
||||
});
|
||||
|
||||
oauth.doLogin("test-user@localhost", "password");
|
||||
|
||||
Event loginEvent = events.expectLogin().assertEvent();
|
||||
|
||||
String codeId = loginEvent.getDetails().get(Details.CODE_ID);
|
||||
loginEvent.getSessionId();
|
||||
|
||||
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
|
||||
OAuthClient.AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
|
||||
Assert.assertEquals(400, response.getStatusCode());
|
||||
|
||||
AssertEvents.ExpectedEvent expectedEvent = events.expectCodeToToken(codeId, null);
|
||||
expectedEvent.error("invalid_code").removeDetail(Details.TOKEN_ID).removeDetail(Details.REFRESH_TOKEN_ID).client((String) null).user((String) null);
|
||||
expectedEvent.assertEvent();
|
||||
|
||||
events.clear();
|
||||
|
||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
appRealm.setAccessCodeLifespan(60);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessTokenCodeUsed() {
|
||||
oauth.doLogin("test-user@localhost", "password");
|
||||
|
||||
Event loginEvent = events.expectLogin().assertEvent();
|
||||
|
||||
String codeId = loginEvent.getDetails().get(Details.CODE_ID);
|
||||
loginEvent.getSessionId();
|
||||
|
||||
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||
OAuthClient.AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
|
||||
Assert.assertEquals(200, response.getStatusCode());
|
||||
|
||||
events.clear();
|
||||
|
||||
response = oauth.doAccessTokenRequest(code, "password");
|
||||
Assert.assertEquals(400, response.getStatusCode());
|
||||
|
||||
AssertEvents.ExpectedEvent expectedEvent = events.expectCodeToToken(codeId, null);
|
||||
expectedEvent.error("invalid_code").removeDetail(Details.TOKEN_ID).removeDetail(Details.REFRESH_TOKEN_ID).client((String) null).user((String) null);
|
||||
expectedEvent.assertEvent();
|
||||
|
||||
events.clear();
|
||||
|
||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
appRealm.setAccessCodeLifespan(60);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessTokenCodeHasRequiredAction() {
|
||||
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel defaultRealm, RealmModel appRealm) {
|
||||
UserModel user = manager.getSession().users().getUserByUsername("test-user@localhost", appRealm);
|
||||
user.addRequiredAction(UserModel.RequiredAction.UPDATE_PROFILE);
|
||||
}
|
||||
});
|
||||
|
||||
oauth.doLogin("test-user@localhost", "password");
|
||||
|
||||
String code = driver.getPageSource().split("code=")[1].split("&")[0].split("\"")[0];
|
||||
|
||||
OAuthClient.AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
|
||||
Assert.assertEquals(400, response.getStatusCode());
|
||||
|
||||
Event event = events.poll();
|
||||
assertNotNull(event.getDetails().get(Details.CODE_ID));
|
||||
|
||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
manager.getSession().users().getUserByUsername("test-user@localhost", appRealm).removeRequiredAction(UserModel.RequiredAction.UPDATE_PROFILE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateAccessToken() throws Exception {
|
||||
Client client = ClientBuilder.newClient();
|
||||
UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
|
||||
URI grantUri = TokenService.grantAccessTokenUrl(builder).build("test");
|
||||
WebTarget grantTarget = client.target(grantUri);
|
||||
builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
|
||||
URI validateUri = TokenService.validateAccessTokenUrl(builder).build("test");
|
||||
WebTarget validateTarget = client.target(validateUri);
|
||||
|
||||
{
|
||||
Response response = validateTarget.queryParam("access_token", "bad token").request().get();
|
||||
Assert.assertEquals(400, response.getStatus());
|
||||
HashMap<String, String> error = response.readEntity(new GenericType <HashMap<String, String>>() {});
|
||||
Assert.assertNotNull(error.get("error"));
|
||||
}
|
||||
|
||||
|
||||
org.keycloak.representations.AccessTokenResponse tokenResponse = null;
|
||||
{
|
||||
String header = BasicAuthHelper.createHeader("test-app", "password");
|
||||
Form form = new Form();
|
||||
form.param("username", "test-user@localhost")
|
||||
.param("password", "password");
|
||||
Response response = grantTarget.request()
|
||||
.header(HttpHeaders.AUTHORIZATION, header)
|
||||
.post(Entity.form(form));
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
|
||||
response.close();
|
||||
}
|
||||
|
||||
{
|
||||
Response response = validateTarget.queryParam("access_token", tokenResponse.getToken()).request().get();
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
AccessToken token = response.readEntity(AccessToken.class);
|
||||
Assert.assertNotNull(token);
|
||||
response.close();
|
||||
}
|
||||
{
|
||||
builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
|
||||
URI logoutUri = TokenService.logoutUrl(builder).build("test");
|
||||
Response response = client.target(logoutUri).queryParam("session_state", tokenResponse.getSessionState()).request().get();
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
response.close();
|
||||
}
|
||||
{
|
||||
Response response = validateTarget.queryParam("access_token", tokenResponse.getToken()).request().get();
|
||||
Assert.assertEquals(400, response.getStatus());
|
||||
HashMap<String, String> error = response.readEntity(new GenericType <HashMap<String, String>>() {});
|
||||
Assert.assertNotNull(error.get("error"));
|
||||
}
|
||||
|
||||
client.close();
|
||||
events.clear();
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.RefreshToken;
|
||||
import org.keycloak.services.resources.TokenService;
|
||||
import org.keycloak.testsuite.AssertEvents;
|
||||
import org.keycloak.testsuite.OAuthClient;
|
||||
import org.keycloak.testsuite.OAuthClient.AccessTokenResponse;
|
||||
|
@ -41,9 +42,22 @@ 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.keycloak.util.BasicAuthHelper;
|
||||
import org.keycloak.util.Time;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
import javax.ws.rs.client.Client;
|
||||
import javax.ws.rs.client.ClientBuilder;
|
||||
import javax.ws.rs.client.Entity;
|
||||
import javax.ws.rs.client.WebTarget;
|
||||
import javax.ws.rs.core.Form;
|
||||
import javax.ws.rs.core.GenericType;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||
|
@ -75,6 +89,33 @@ public class RefreshTokenTest {
|
|||
@Rule
|
||||
public AssertEvents events = new AssertEvents(keycloakRule);
|
||||
|
||||
/**
|
||||
* KEYCLOAK-547
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void nullRefreshToken() throws Exception {
|
||||
Client client = ClientBuilder.newClient();
|
||||
UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
|
||||
URI uri = TokenService.refreshUrl(builder).build("test");
|
||||
WebTarget target = client.target(uri);
|
||||
|
||||
org.keycloak.representations.AccessTokenResponse tokenResponse = null;
|
||||
{
|
||||
String header = BasicAuthHelper.createHeader("test-app", "password");
|
||||
Form form = new Form();
|
||||
Response response = target.request()
|
||||
.header(HttpHeaders.AUTHORIZATION, header)
|
||||
.post(Entity.form(form));
|
||||
Assert.assertEquals(400, response.getStatus());
|
||||
response.close();
|
||||
}
|
||||
events.clear();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void refreshTokenRequest() throws Exception {
|
||||
oauth.doLogin("test-user@localhost", "password");
|
||||
|
|
Loading…
Reference in a new issue