From 79c1230a9d65cd14708bd8c60b3291cbbb4e632c Mon Sep 17 00:00:00 2001 From: Stian Thorgersen Date: Thu, 17 Oct 2013 15:00:46 +0100 Subject: [PATCH] Added redirect uris to application --- .../idm/ApplicationRepresentation.java | 9 ++ .../resources/forms/theme/default/error.ftl | 3 +- .../java/org/keycloak/models/UserModel.java | 8 ++ .../org/keycloak/models/utils/ArrayUtils.java | 31 ---- .../models/picketlink/UserAdapter.java | 135 +++++++++++------- .../services/managers/ApplicationManager.java | 21 +++ .../services/resources/flows/OAuthFlows.java | 5 + .../java/org/keycloak/test/AdapterTest.java | 38 ----- .../keycloak/test/ApplicationModelTest.java | 100 +++++++++++++ .../java/org/keycloak/test/UserModelTest.java | 118 +++++++++++++++ .../oauth/AuthorizationCodeTest.java | 59 +++++++- .../keycloak/testsuite/pages/ErrorPage.java | 54 +++++++ 12 files changed, 454 insertions(+), 127 deletions(-) delete mode 100755 model/api/src/main/java/org/keycloak/models/utils/ArrayUtils.java create mode 100644 services/src/test/java/org/keycloak/test/ApplicationModelTest.java create mode 100644 services/src/test/java/org/keycloak/test/UserModelTest.java create mode 100644 testsuite/integration/src/test/java/org/keycloak/testsuite/pages/ErrorPage.java 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 ab12aae383..7b7fa9d48a 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 roles; protected List roleMappings; protected List scopeMappings; + protected List redirectUris; public String getSelf() { return self; @@ -146,4 +147,12 @@ public class ApplicationRepresentation { public void setUseRealmMappings(boolean useRealmMappings) { this.useRealmMappings = useRealmMappings; } + + public List getRedirectUris() { + return redirectUris; + } + + public void setRedirectUris(List 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 64ca460b7a..659fce1e1a 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">

Something happened and we could not process your request.

-

${error.summary}

- Go to the homepage ยป +

${error.summary}

<#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 2131d3ca91..8598ae765d 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 getRedirectUris(); + + void setRedirectUris(Set redirectUris); + + void addRedirectUri(String redirectUri); + + void removeRedirectUri(String redirectUri); + String getFirstName(); void setFirstName(String firstName); diff --git a/model/api/src/main/java/org/keycloak/models/utils/ArrayUtils.java b/model/api/src/main/java/org/keycloak/models/utils/ArrayUtils.java deleted file mode 100755 index 70c2b1e7b8..0000000000 --- a/model/api/src/main/java/org/keycloak/models/utils/ArrayUtils.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.keycloak.models.utils; - -import java.lang.reflect.Array; -import java.util.Arrays; - -public class ArrayUtils { - - public static T[] add(T[] src, T o) { - T[] dst = Arrays.copyOf(src, src.length + 1); - dst[src.length] = o; - return dst; - } - - public static T[] remove(T[] src, T o) { - int l = Arrays.binarySearch(src, o); - if (l < 0) { - return src; - } - - T[] dst = newInstance(o, src.length - 1); - System.arraycopy(src, 0, dst, 0, l); - System.arraycopy(src, l + 1, dst, l, dst.length - l); - return dst; - } - - @SuppressWarnings("unchecked") - private static T[] newInstance(T type, int length) { - return (T[]) Array.newInstance(type.getClass(), length); - } - -} 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 de303b43c8..98894ced7e 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 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 getAttributes() { Map attributes = new HashMap(); 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 getRequiredActions() { - RequiredAction[] actions = getRequiredActionsArray(); - if (actions == null) { - return Collections.emptySet(); - } else { - Set s = new HashSet(); - 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); - } - } - - Attribute a = new Attribute(REQUIRED_ACTIONS_ATTR, actions); - - user.setAttribute(a); - idm.update(user); + addToAttributeSet(REQUIRED_ACTIONS_ATTR, action); } @Override public void removeRequiredAction(RequiredAction action) { - RequiredAction[] actions = getRequiredActionsArray(); - if (actions != null) { - if (Arrays.binarySearch(actions, action) >= 0) { - actions = ArrayUtils.remove(actions, action); + removeFromAttributeSet(REQUIRED_ACTIONS_ATTR, action); + } - if (actions.length == 0) { - user.removeAttribute(REQUIRED_ACTIONS_ATTR); - } else { - Attribute a = new Attribute(REQUIRED_ACTIONS_ATTR, actions); - user.setAttribute(a); - } + @Override + public Set getRedirectUris() { + return getAttributeSet(REDIRECT_URIS); + } - idm.update(user); - } - } + @Override + public void setRedirectUris(Set redirectUris) { + setAttributeSet(REDIRECT_URIS, redirectUris); + } + + @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 Set getAttributeSet(String name) { + Attribute a = user.getAttribute(name); + + Set s = new HashSet(); + + 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) s; + } + + private void setAttributeSet(String name, Set set) { + if (set.isEmpty()) { + user.removeAttribute(name); + } else { + user.setAttribute(new Attribute(name, set.toArray(new Serializable[set.size()]))); + } + idm.update(user); + } + + private void addToAttributeSet(String name, T t) { + Set set = getAttributeSet(name); + if (set == null) { + set = new HashSet(); + } + + if (set.add(t)) { + setAttributeSet(name, set); + idm.update(user); + } + } + + private void removeFromAttributeSet(String name, T t) { + Set 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 7156f89bc1..93c29599d4 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 redirectUris = rep.getRedirectUris(); + if (redirectUris != null) { + resource.getApplicationUser().setRedirectUris(new HashSet(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 redirectUris = applicationModel.getApplicationUser().getRedirectUris(); + if (redirectUris != null) { + rep.setRedirectUris(new LinkedList(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 5d01a39cf1..a9bc79b26e 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 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 7342e5e351..22c38b3ef4 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 0000000000..446607938a --- /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 Stian Thorgersen + */ +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 expected, List actual) { + Assert.assertEquals(expected.size(), actual.size()); + Iterator exp = expected.iterator(); + Iterator 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 0000000000..9922596cfb --- /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 Stian Thorgersen + */ +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 expected, List actual) { + Assert.assertEquals(expected.size(), actual.size()); + Iterator exp = expected.iterator(); + Iterator 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 e6a89bd23d..2ccd506a9b 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 0000000000..bfe3201984 --- /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 Stian Thorgersen + */ +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(); + } + +}