Details
diff --git a/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
index ab12aae..7b7fa9d 100755
--- a/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
@@ -20,6 +20,7 @@ public class ApplicationRepresentation {
protected List<RoleRepresentation> roles;
protected List<UserRoleMappingRepresentation> roleMappings;
protected List<ScopeMappingRepresentation> scopeMappings;
+ protected List<String> redirectUris;
public String getSelf() {
return self;
@@ -146,4 +147,12 @@ public class ApplicationRepresentation {
public void setUseRealmMappings(boolean useRealmMappings) {
this.useRealmMappings = useRealmMappings;
}
+
+ public List<String> getRedirectUris() {
+ return redirectUris;
+ }
+
+ public void setRedirectUris(List<String> redirectUris) {
+ this.redirectUris = redirectUris;
+ }
}
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/error.ftl b/forms/src/main/resources/META-INF/resources/forms/theme/default/error.ftl
index 64ca460..659fce1 100755
--- a/forms/src/main/resources/META-INF/resources/forms/theme/default/error.ftl
+++ b/forms/src/main/resources/META-INF/resources/forms/theme/default/error.ftl
@@ -12,8 +12,7 @@
<#elseif section = "form">
<p class="instruction">Something happened and we could not process your request.</p>
- <p class="instruction second">${error.summary}</p>
- <a href="saas-login.html" class="link-right">Go to the homepage »</a>
+ <p id="error-summary" class="instruction second">${error.summary}</p>
<#elseif section = "info" >
diff --git a/model/api/src/main/java/org/keycloak/models/UserModel.java b/model/api/src/main/java/org/keycloak/models/UserModel.java
index 2131d3c..8598ae7 100755
--- a/model/api/src/main/java/org/keycloak/models/UserModel.java
+++ b/model/api/src/main/java/org/keycloak/models/UserModel.java
@@ -35,6 +35,14 @@ public interface UserModel {
void removeRequiredAction(RequiredAction action);
+ Set<String> getRedirectUris();
+
+ void setRedirectUris(Set<String> redirectUris);
+
+ void addRedirectUri(String redirectUri);
+
+ void removeRedirectUri(String redirectUri);
+
String getFirstName();
void setFirstName(String firstName);
diff --git a/model/picketlink/src/main/java/org/keycloak/models/picketlink/UserAdapter.java b/model/picketlink/src/main/java/org/keycloak/models/picketlink/UserAdapter.java
index de303b4..98894ce 100755
--- a/model/picketlink/src/main/java/org/keycloak/models/picketlink/UserAdapter.java
+++ b/model/picketlink/src/main/java/org/keycloak/models/picketlink/UserAdapter.java
@@ -1,6 +1,6 @@
package org.keycloak.models.picketlink;
-import java.util.Arrays;
+import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -8,7 +8,6 @@ import java.util.Map;
import java.util.Set;
import org.keycloak.models.UserModel;
-import org.keycloak.models.utils.ArrayUtils;
import org.picketlink.idm.IdentityManager;
import org.picketlink.idm.model.Attribute;
import org.picketlink.idm.model.sample.User;
@@ -22,6 +21,8 @@ public class UserAdapter implements UserModel {
private static final String KEYCLOAK_TOTP_ATTR = "totpEnabled";
private static final String REQUIRED_ACTIONS_ATTR = "requiredActions";
+ private static final String REDIRECT_URIS = "redirectUris";
+
protected User user;
protected IdentityManager idm;
@@ -110,7 +111,8 @@ public class UserAdapter implements UserModel {
@Override
public String getAttribute(String name) {
Attribute<String> attribute = user.getAttribute(name);
- if (attribute == null || attribute.getValue() == null) return null;
+ if (attribute == null || attribute.getValue() == null)
+ return null;
return attribute.getValue().toString();
}
@@ -118,73 +120,45 @@ public class UserAdapter implements UserModel {
public Map<String, String> getAttributes() {
Map<String, String> attributes = new HashMap<String, String>();
for (Attribute<?> attribute : user.getAttributes()) {
- if (attribute.getValue() != null) attributes.put(attribute.getName(), attribute.getValue().toString());
+ if (attribute.getValue() != null)
+ attributes.put(attribute.getName(), attribute.getValue().toString());
}
return attributes;
}
- private RequiredAction[] getRequiredActionsArray() {
- Attribute<?> a = user.getAttribute(REQUIRED_ACTIONS_ATTR);
- if (a == null) {
- return null;
- }
-
- Object o = a.getValue();
- if (o instanceof RequiredAction) {
- return new RequiredAction[] { (RequiredAction) o };
- } else {
- return (RequiredAction[]) o;
- }
- }
-
@Override
public Set<RequiredAction> getRequiredActions() {
- RequiredAction[] actions = getRequiredActionsArray();
- if (actions == null) {
- return Collections.emptySet();
- } else {
- Set<RequiredAction> s = new HashSet<RequiredAction>();
- for (RequiredAction a : actions) {
- s.add(a);
- }
- return Collections.unmodifiableSet(s);
- }
+ return getAttributeSet(REQUIRED_ACTIONS_ATTR);
}
@Override
public void addRequiredAction(RequiredAction action) {
- RequiredAction[] actions = getRequiredActionsArray();
- if (actions == null) {
- actions = new RequiredAction[] { action };
- } else {
- if (Arrays.binarySearch(actions, action) < 0) {
- actions = ArrayUtils.add(actions, action);
- }
- }
+ addToAttributeSet(REQUIRED_ACTIONS_ATTR, action);
+ }
- Attribute<RequiredAction[]> a = new Attribute<RequiredAction[]>(REQUIRED_ACTIONS_ATTR, actions);
+ @Override
+ public void removeRequiredAction(RequiredAction action) {
+ removeFromAttributeSet(REQUIRED_ACTIONS_ATTR, action);
+ }
- user.setAttribute(a);
- idm.update(user);
+ @Override
+ public Set<String> getRedirectUris() {
+ return getAttributeSet(REDIRECT_URIS);
}
@Override
- public void removeRequiredAction(RequiredAction action) {
- RequiredAction[] actions = getRequiredActionsArray();
- if (actions != null) {
- if (Arrays.binarySearch(actions, action) >= 0) {
- actions = ArrayUtils.remove(actions, action);
-
- if (actions.length == 0) {
- user.removeAttribute(REQUIRED_ACTIONS_ATTR);
- } else {
- Attribute<RequiredAction[]> a = new Attribute<RequiredAction[]>(REQUIRED_ACTIONS_ATTR, actions);
- user.setAttribute(a);
- }
+ public void setRedirectUris(Set<String> redirectUris) {
+ setAttributeSet(REDIRECT_URIS, redirectUris);
+ }
- idm.update(user);
- }
- }
+ @Override
+ public void addRedirectUri(String redirectUri) {
+ addToAttributeSet(REDIRECT_URIS, redirectUri);
+ }
+
+ @Override
+ public void removeRedirectUri(String redirectUri) {
+ removeFromAttributeSet(REDIRECT_URIS, redirectUri);
}
@Override
@@ -199,4 +173,57 @@ public class UserAdapter implements UserModel {
idm.update(user);
}
+ @SuppressWarnings("unchecked")
+ private <T extends Serializable> Set<T> getAttributeSet(String name) {
+ Attribute<Serializable> a = user.getAttribute(name);
+
+ Set<Serializable> s = new HashSet<Serializable>();
+
+ if (a != null) {
+ Serializable o = a.getValue();
+ if (o instanceof Serializable[]) {
+ for (Serializable t : (Serializable[]) o) {
+ s.add(t);
+ }
+ } else {
+ s.add(o);
+ }
+ }
+
+ return (Set<T>) s;
+ }
+
+ private <T extends Serializable> void setAttributeSet(String name, Set<T> set) {
+ if (set.isEmpty()) {
+ user.removeAttribute(name);
+ } else {
+ user.setAttribute(new Attribute<Serializable[]>(name, set.toArray(new Serializable[set.size()])));
+ }
+ idm.update(user);
+ }
+
+ private <T extends Serializable> void addToAttributeSet(String name, T t) {
+ Set<Serializable> set = getAttributeSet(name);
+ if (set == null) {
+ set = new HashSet<Serializable>();
+ }
+
+ if (set.add(t)) {
+ setAttributeSet(name, set);
+ idm.update(user);
+ }
+ }
+
+ private <T extends Serializable> void removeFromAttributeSet(String name, T t) {
+ Set<Serializable> set = getAttributeSet(name);
+ if (set == null) {
+ return;
+ }
+
+ if (set.remove(t)) {
+ setAttributeSet(name, set);
+ idm.update(user);
+ }
+ }
+
}
diff --git a/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java b/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java
index 7156f89..93c2959 100755
--- a/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java
@@ -1,5 +1,10 @@
package org.keycloak.services.managers;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
import org.keycloak.models.*;
import org.keycloak.representations.idm.*;
@@ -32,6 +37,12 @@ public class ApplicationManager {
realm.updateCredential(resourceUser, credential);
}
}
+ if (resourceRep.getRedirectUris() != null) {
+ for (String redirectUri : resourceRep.getRedirectUris()) {
+ resourceUser.addRedirectUri(redirectUri);
+ }
+ }
+
realm.grantRole(resourceUser, loginRole);
@@ -82,6 +93,10 @@ public class ApplicationManager {
resource.setSurrogateAuthRequired(rep.isSurrogateAuthRequired());
resource.updateApplication();
+ List<String> redirectUris = rep.getRedirectUris();
+ if (redirectUris != null) {
+ resource.getApplicationUser().setRedirectUris(new HashSet<String>(redirectUris));
+ }
}
public ApplicationRepresentation toRepresentation(ApplicationModel applicationModel) {
@@ -92,6 +107,12 @@ public class ApplicationManager {
rep.setAdminUrl(applicationModel.getManagementUrl());
rep.setSurrogateAuthRequired(applicationModel.isSurrogateAuthRequired());
rep.setBaseUrl(applicationModel.getBaseUrl());
+
+ Set<String> redirectUris = applicationModel.getApplicationUser().getRedirectUris();
+ if (redirectUris != null) {
+ rep.setRedirectUris(new LinkedList<String>(redirectUris));
+ }
+
return rep;
}
diff --git a/services/src/main/java/org/keycloak/services/resources/flows/OAuthFlows.java b/services/src/main/java/org/keycloak/services/resources/flows/OAuthFlows.java
index 5d01a39..a9bc79b 100755
--- a/services/src/main/java/org/keycloak/services/resources/flows/OAuthFlows.java
+++ b/services/src/main/java/org/keycloak/services/resources/flows/OAuthFlows.java
@@ -68,6 +68,11 @@ public class OAuthFlows {
}
public Response redirectAccessCode(AccessCodeEntry accessCode, String state, String redirect) {
+ Set<String> redirectUris = accessCode.getClient().getRedirectUris();
+ if (!redirectUris.isEmpty() && !redirectUris.contains(redirect)) {
+ return forwardToSecurityFailure("Invalid redirect_uri " + redirect);
+ }
+
String code = accessCode.getCode();
UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("code", code);
log.info("redirectAccessCode: state: " + state);
diff --git a/services/src/test/java/org/keycloak/test/AdapterTest.java b/services/src/test/java/org/keycloak/test/AdapterTest.java
index 7342e5e..22c38b3 100755
--- a/services/src/test/java/org/keycloak/test/AdapterTest.java
+++ b/services/src/test/java/org/keycloak/test/AdapterTest.java
@@ -302,42 +302,4 @@ public class AdapterTest extends AbstractKeycloakTest {
Assert.assertEquals("user", role.getName());
}
- @Test
- public void testUserRequiredActions() throws Exception {
- test1CreateRealm();
-
- UserModel user = realmModel.addUser("bburke");
-
- Assert.assertTrue(user.getRequiredActions().isEmpty());
-
- user.addRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP);
- user = realmModel.getUser("bburke");
-
- Assert.assertEquals(1, user.getRequiredActions().size());
- Assert.assertTrue(user.getRequiredActions().contains(RequiredAction.CONFIGURE_TOTP));
-
- user.addRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP);
- user = realmModel.getUser("bburke");
-
- Assert.assertEquals(1, user.getRequiredActions().size());
- Assert.assertTrue(user.getRequiredActions().contains(RequiredAction.CONFIGURE_TOTP));
-
- user.addRequiredAction(UserModel.RequiredAction.VERIFY_EMAIL);
- user = realmModel.getUser("bburke");
-
- Assert.assertEquals(2, user.getRequiredActions().size());
- Assert.assertTrue(user.getRequiredActions().contains(RequiredAction.CONFIGURE_TOTP));
- Assert.assertTrue(user.getRequiredActions().contains(RequiredAction.VERIFY_EMAIL));
-
- user.removeRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP);
- user = realmModel.getUser("bburke");
-
- Assert.assertEquals(1, user.getRequiredActions().size());
- Assert.assertTrue(user.getRequiredActions().contains(RequiredAction.VERIFY_EMAIL));
-
- user.removeRequiredAction(UserModel.RequiredAction.VERIFY_EMAIL);
- user = realmModel.getUser("bburke");
-
- Assert.assertTrue(user.getRequiredActions().isEmpty());
- }
}
diff --git a/services/src/test/java/org/keycloak/test/ApplicationModelTest.java b/services/src/test/java/org/keycloak/test/ApplicationModelTest.java
new file mode 100644
index 0000000..4466079
--- /dev/null
+++ b/services/src/test/java/org/keycloak/test/ApplicationModelTest.java
@@ -0,0 +1,100 @@
+package org.keycloak.test;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.representations.idm.ApplicationRepresentation;
+import org.keycloak.services.managers.ApplicationManager;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.services.resources.KeycloakApplication;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ApplicationModelTest extends AbstractKeycloakServerTest {
+ private KeycloakSessionFactory factory;
+ private KeycloakSession identitySession;
+ private RealmManager manager;
+ private ApplicationModel application;
+ private RealmModel realm;
+ private ApplicationManager appManager;
+
+ @Before
+ public void before() throws Exception {
+ factory = KeycloakApplication.buildSessionFactory();
+ identitySession = factory.createSession();
+ identitySession.getTransaction().begin();
+ manager = new RealmManager(identitySession);
+
+ appManager = new ApplicationManager(manager);
+
+ realm = manager.createRealm("original");
+ application = realm.addApplication("application");
+ application.setBaseUrl("http://base");
+ application.setManagementUrl("http://management");
+ application.setName("app-name");
+ application.addRole("role-1");
+ application.addRole("role-2");
+
+ application.getApplicationUser().addRedirectUri("redirect-1");
+ application.getApplicationUser().addRedirectUri("redirect-2");
+
+ application.updateApplication();
+ }
+
+ @After
+ public void after() throws Exception {
+ identitySession.getTransaction().commit();
+ identitySession.close();
+ factory.close();
+ }
+
+ @Test
+ public void persist() {
+ RealmModel persisted = manager.getRealm(realm.getId());
+
+ assertEquals(application, persisted.getApplications().get(0));
+ }
+
+ @Test
+ public void json() {
+ ApplicationRepresentation representation = appManager.toRepresentation(application);
+
+ RealmModel realm = manager.createRealm("copy");
+ ApplicationModel copy = appManager.createApplication(realm, representation);
+
+ assertEquals(application, copy);
+ }
+
+ public static void assertEquals(ApplicationModel expected, ApplicationModel actual) {
+ Assert.assertEquals(expected.getName(), actual.getName());
+ Assert.assertEquals(expected.getBaseUrl(), actual.getBaseUrl());
+ Assert.assertEquals(expected.getManagementUrl(), actual.getManagementUrl());
+
+ UserModel auser = actual.getApplicationUser();
+ UserModel euser = expected.getApplicationUser();
+
+ Assert.assertTrue(euser.getRedirectUris().containsAll(auser.getRedirectUris()));
+ }
+
+ public static void assertEquals(List<RoleModel> expected, List<RoleModel> actual) {
+ Assert.assertEquals(expected.size(), actual.size());
+ Iterator<RoleModel> exp = expected.iterator();
+ Iterator<RoleModel> act = actual.iterator();
+ while (exp.hasNext()) {
+ Assert.assertEquals(exp.next().getName(), act.next().getName());
+ }
+ }
+
+}
+
diff --git a/services/src/test/java/org/keycloak/test/UserModelTest.java b/services/src/test/java/org/keycloak/test/UserModelTest.java
new file mode 100644
index 0000000..9922596
--- /dev/null
+++ b/services/src/test/java/org/keycloak/test/UserModelTest.java
@@ -0,0 +1,118 @@
+package org.keycloak.test;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserModel.RequiredAction;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.services.resources.KeycloakApplication;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class UserModelTest extends AbstractKeycloakServerTest {
+ private KeycloakSessionFactory factory;
+ private KeycloakSession identitySession;
+ private RealmManager manager;
+
+ @Before
+ public void before() throws Exception {
+ factory = KeycloakApplication.buildSessionFactory();
+ identitySession = factory.createSession();
+ identitySession.getTransaction().begin();
+ manager = new RealmManager(identitySession);
+ }
+
+ @After
+ public void after() throws Exception {
+ identitySession.getTransaction().commit();
+ identitySession.close();
+ factory.close();
+ }
+
+ @Test
+ public void persistUser() {
+ RealmModel realm = manager.createRealm("original");
+ UserModel user = realm.addUser("user");
+ user.setFirstName("first-name");
+ user.setLastName("last-name");
+ user.setEmail("email");
+
+ user.addRedirectUri("redirect-1");
+ user.addRedirectUri("redirect-2");
+
+ user.addRequiredAction(RequiredAction.CONFIGURE_TOTP);
+ user.addRequiredAction(RequiredAction.UPDATE_PASSWORD);
+
+ UserModel persisted = manager.getRealm(realm.getId()).getUser("user");
+
+ assertEquals(user, persisted);
+ }
+
+ @Test
+ public void testUserRequiredActions() throws Exception {
+ RealmModel realm = manager.createRealm("original");
+ UserModel user = realm.addUser("user");
+
+ Assert.assertTrue(user.getRequiredActions().isEmpty());
+
+ user.addRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP);
+ user = realm.getUser("user");
+
+ Assert.assertEquals(1, user.getRequiredActions().size());
+ Assert.assertTrue(user.getRequiredActions().contains(RequiredAction.CONFIGURE_TOTP));
+
+ user.addRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP);
+ user = realm.getUser("user");
+
+ Assert.assertEquals(1, user.getRequiredActions().size());
+ Assert.assertTrue(user.getRequiredActions().contains(RequiredAction.CONFIGURE_TOTP));
+
+ user.addRequiredAction(UserModel.RequiredAction.VERIFY_EMAIL);
+ user = realm.getUser("user");
+
+ Assert.assertEquals(2, user.getRequiredActions().size());
+ Assert.assertTrue(user.getRequiredActions().contains(RequiredAction.CONFIGURE_TOTP));
+ Assert.assertTrue(user.getRequiredActions().contains(RequiredAction.VERIFY_EMAIL));
+
+ user.removeRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP);
+ user = realm.getUser("user");
+
+ Assert.assertEquals(1, user.getRequiredActions().size());
+ Assert.assertTrue(user.getRequiredActions().contains(RequiredAction.VERIFY_EMAIL));
+
+ user.removeRequiredAction(UserModel.RequiredAction.VERIFY_EMAIL);
+ user = realm.getUser("user");
+
+ Assert.assertTrue(user.getRequiredActions().isEmpty());
+ }
+
+ public static void assertEquals(UserModel expected, UserModel actual) {
+ Assert.assertEquals(expected.getLoginName(), actual.getLoginName());
+ Assert.assertEquals(expected.getFirstName(), actual.getFirstName());
+ Assert.assertEquals(expected.getLastName(), actual.getLastName());
+ Assert.assertArrayEquals(expected.getRedirectUris().toArray(), actual.getRedirectUris().toArray());
+ Assert.assertArrayEquals(expected.getRequiredActions().toArray(), actual.getRequiredActions().toArray());
+
+ }
+
+ public static void assertEquals(List<RoleModel> expected, List<RoleModel> actual) {
+ Assert.assertEquals(expected.size(), actual.size());
+ Iterator<RoleModel> exp = expected.iterator();
+ Iterator<RoleModel> act = actual.iterator();
+ while (exp.hasNext()) {
+ Assert.assertEquals(exp.next().getName(), act.next().getName());
+ }
+ }
+
+}
+
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
index e6a89bd..2ccd506 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
@@ -28,8 +28,13 @@ import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.OAuthClient;
import org.keycloak.testsuite.OAuthClient.AuthorizationCodeResponse;
+import org.keycloak.testsuite.pages.ErrorPage;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.rule.KeycloakRule;
import org.keycloak.testsuite.rule.WebResource;
@@ -56,8 +61,11 @@ public class AuthorizationCodeTest {
@WebResource
protected LoginPage loginPage;
+ @WebResource
+ protected ErrorPage errorPage;
+
@Test
- public void authorizationRequest() throws ClientProtocolException, IOException {
+ public void authorizationRequest() throws IOException {
oauth.state("mystate");
AuthorizationCodeResponse response = oauth.doLogin("test-user@localhost", "password");
@@ -69,7 +77,54 @@ public class AuthorizationCodeTest {
}
@Test
- public void authorizationRequestNoState() throws ClientProtocolException, IOException {
+ public void authorizationValidRedirectUri() throws IOException {
+ keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
+ @Override
+ public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+ for (ApplicationModel app : appRealm.getApplications()) {
+ if (app.getName().equals("test-app")) {
+ UserModel client = app.getApplicationUser();
+ client.addRedirectUri(oauth.getRedirectUri());
+ }
+ }
+ }
+ });
+
+ oauth.state("mystate");
+
+ AuthorizationCodeResponse response = oauth.doLogin("test-user@localhost", "password");
+
+ Assert.assertTrue(response.isRedirected());
+ Assert.assertNotNull(response.getCode());
+ }
+
+ @Test
+ public void authorizationRequestInvalidRedirectUri() throws IOException {
+ keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
+ @Override
+ public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+ for (ApplicationModel app : appRealm.getApplications()) {
+ if (app.getName().equals("test-app")) {
+ UserModel client = app.getApplicationUser();
+ client.addRedirectUri(oauth.getRedirectUri());
+ }
+ }
+ }
+ });
+
+ oauth.redirectUri("http://invalid");
+ oauth.state("mystate");
+
+ AuthorizationCodeResponse response = oauth.doLogin("test-user@localhost", "password");
+
+ Assert.assertFalse(response.isRedirected());
+
+ Assert.assertTrue(errorPage.isCurrent());
+ Assert.assertEquals("Invalid redirect_uri http://invalid", errorPage.getError());
+ }
+
+ @Test
+ public void authorizationRequestNoState() throws IOException {
AuthorizationCodeResponse response = oauth.doLogin("test-user@localhost", "password");
Assert.assertTrue(response.isRedirected());
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/ErrorPage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/ErrorPage.java
new file mode 100644
index 0000000..bfe3201
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/ErrorPage.java
@@ -0,0 +1,54 @@
+/*
+ * 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.pages;
+
+import org.keycloak.testsuite.OAuthClient;
+import org.keycloak.testsuite.rule.WebResource;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ErrorPage extends Page {
+
+ @WebResource
+ protected OAuthClient oauth;
+
+ @FindBy(id = "error-summary")
+ private WebElement errorMessage;
+
+ public String getError() {
+ return errorMessage.getText();
+ }
+
+ public boolean isCurrent() {
+ return driver.getTitle().equals("We're sorry...");
+ }
+
+ @Override
+ public void open() {
+ throw new UnsupportedOperationException();
+ }
+
+}