Merge pull request #263 from stianst/master
Added support for any port with http://localhost redirect uri. Added Config to centralize system properties used to configure KC
This commit is contained in:
commit
d0a6a8ae3b
21 changed files with 211 additions and 60 deletions
|
@ -71,15 +71,15 @@ module.controller('GlobalCtrl', function($scope, $http, Auth, Current, $location
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
module.controller('HomeCtrl', function(Realm, $location) {
|
module.controller('HomeCtrl', function(Realm, Auth, $location) {
|
||||||
Realm.query(null, function(realms) {
|
Realm.query(null, function(realms) {
|
||||||
var realm;
|
var realm;
|
||||||
if (realms.length == 1) {
|
if (realms.length == 1) {
|
||||||
realm = realms[0].realm;
|
realm = realms[0].realm;
|
||||||
} else if (realms.length == 2) {
|
} else if (realms.length == 2) {
|
||||||
if (realms[0].realm == 'keycloak-admin') {
|
if (realms[0].realm == Auth.user.realm) {
|
||||||
realm = realms[1].realm;
|
realm = realms[1].realm;
|
||||||
} else if (realms[1].realm == 'administration') {
|
} else if (realms[1].realm == Auth.user.realm) {
|
||||||
realm = realms[0].realm;
|
realm = realms[0].realm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
{{auth.user.displayName}}<b class="caret"></b>
|
{{auth.user.displayName}}<b class="caret"></b>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li><a href="/auth/rest/realms/keycloak-admin/account?referrer=admin-console">Manage Account</a></li>
|
<li><a href="/auth/rest/realms/{{auth.user.realm}}/account?referrer=admin-console">Manage Account</a></li>
|
||||||
<li class="separator"><a href="/auth/rest/admin/logout">Sign Out</a></li>
|
<li class="separator"><a href="/auth/rest/admin/logout">Sign Out</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -18,6 +18,11 @@
|
||||||
<artifactId>keycloak-core</artifactId>
|
<artifactId>keycloak-core</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-model-api</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.resteasy</groupId>
|
<groupId>org.jboss.resteasy</groupId>
|
||||||
<artifactId>resteasy-jaxrs</artifactId>
|
<artifactId>resteasy-jaxrs</artifactId>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.keycloak.freemarker;
|
package org.keycloak.freemarker;
|
||||||
|
|
||||||
import org.jboss.resteasy.logging.Logger;
|
import org.jboss.resteasy.logging.Logger;
|
||||||
|
import org.keycloak.models.Config;
|
||||||
import org.keycloak.util.ProviderLoader;
|
import org.keycloak.util.ProviderLoader;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -19,12 +20,10 @@ import java.util.Properties;
|
||||||
public class ThemeLoader {
|
public class ThemeLoader {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(ThemeLoader.class);
|
private static final Logger logger = Logger.getLogger(ThemeLoader.class);
|
||||||
private static String DEFAULT = "keycloak";
|
|
||||||
public static final String BASE = "base";
|
|
||||||
|
|
||||||
public static Theme createTheme(String name, Theme.Type type) throws FreeMarkerException {
|
public static Theme createTheme(String name, Theme.Type type) throws FreeMarkerException {
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
name = DEFAULT;
|
name = Config.getThemeDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ThemeProvider> providers = new LinkedList();
|
List<ThemeProvider> providers = new LinkedList();
|
||||||
|
@ -61,21 +60,21 @@ public class ThemeLoader {
|
||||||
try {
|
try {
|
||||||
return p.createTheme(name, type);
|
return p.createTheme(name, type);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (name.equals(BASE)) {
|
if (name.equals(Config.getThemeBase())) {
|
||||||
throw new FreeMarkerException("Failed to create " + type.toString().toLowerCase() + " theme", e);
|
throw new FreeMarkerException("Failed to create " + type.toString().toLowerCase() + " theme", e);
|
||||||
} else {
|
} else {
|
||||||
logger.error("Failed to create " + type.toString().toLowerCase() + " theme", e);
|
logger.error("Failed to create " + type.toString().toLowerCase() + " theme", e);
|
||||||
return findTheme(providers, BASE, type);
|
return findTheme(providers, Config.getThemeBase(), type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name.equals(BASE)) {
|
if (name.equals(Config.getThemeBase())) {
|
||||||
throw new FreeMarkerException(type.toString().toLowerCase() + " theme '" + name + "' not found");
|
throw new FreeMarkerException(type.toString().toLowerCase() + " theme '" + name + "' not found");
|
||||||
} else {
|
} else {
|
||||||
logger.error(type.toString().toLowerCase() + " theme '" + name + "' not found");
|
logger.error(type.toString().toLowerCase() + " theme '" + name + "' not found");
|
||||||
return findTheme(providers, BASE, type);
|
return findTheme(providers, Config.getThemeBase(), type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@ public class ClassLoaderTheme implements Theme {
|
||||||
|
|
||||||
private final Type type;
|
private final Type type;
|
||||||
|
|
||||||
|
private final ClassLoader classLoader;
|
||||||
|
|
||||||
private final String templateRoot;
|
private final String templateRoot;
|
||||||
|
|
||||||
private final String resourceRoot;
|
private final String resourceRoot;
|
||||||
|
@ -26,9 +28,10 @@ public class ClassLoaderTheme implements Theme {
|
||||||
|
|
||||||
private final Properties properties;
|
private final Properties properties;
|
||||||
|
|
||||||
public ClassLoaderTheme(String name, Type type) throws IOException {
|
public ClassLoaderTheme(String name, Type type, ClassLoader classLoader) throws IOException {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.classLoader = classLoader;
|
||||||
|
|
||||||
String themeRoot = "theme/" + type.toString().toLowerCase() + "/" + name + "/";
|
String themeRoot = "theme/" + type.toString().toLowerCase() + "/" + name + "/";
|
||||||
|
|
||||||
|
@ -37,7 +40,7 @@ public class ClassLoaderTheme implements Theme {
|
||||||
this.messages = themeRoot + "messages/messages.properties";
|
this.messages = themeRoot + "messages/messages.properties";
|
||||||
this.properties = new Properties();
|
this.properties = new Properties();
|
||||||
|
|
||||||
URL p = getClass().getClassLoader().getResource(themeRoot + "theme.properties");
|
URL p = classLoader.getResource(themeRoot + "theme.properties");
|
||||||
if (p != null) {
|
if (p != null) {
|
||||||
properties.load(p.openStream());
|
properties.load(p.openStream());
|
||||||
this.parentName = properties.getProperty("parent");
|
this.parentName = properties.getProperty("parent");
|
||||||
|
@ -63,28 +66,28 @@ public class ClassLoaderTheme implements Theme {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URL getTemplate(String name) {
|
public URL getTemplate(String name) {
|
||||||
return getClass().getClassLoader().getResource(templateRoot + name);
|
return classLoader.getResource(templateRoot + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InputStream getTemplateAsStream(String name) {
|
public InputStream getTemplateAsStream(String name) {
|
||||||
return getClass().getClassLoader().getResourceAsStream(templateRoot + name);
|
return classLoader.getResourceAsStream(templateRoot + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URL getResource(String path) {
|
public URL getResource(String path) {
|
||||||
return getClass().getClassLoader().getResource(resourceRoot + path);
|
return classLoader.getResource(resourceRoot + path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InputStream getResourceAsStream(String path) {
|
public InputStream getResourceAsStream(String path) {
|
||||||
return getClass().getClassLoader().getResourceAsStream(resourceRoot + path);
|
return classLoader.getResourceAsStream(resourceRoot + path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Properties getMessages() throws IOException {
|
public Properties getMessages() throws IOException {
|
||||||
Properties m = new Properties();
|
Properties m = new Properties();
|
||||||
URL url = getClass().getClassLoader().getResource(this.messages);
|
URL url = classLoader.getResource(this.messages);
|
||||||
if (url != null) {
|
if (url != null) {
|
||||||
m.load(url.openStream());
|
m.load(url.openStream());
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package org.keycloak.theme;
|
||||||
import org.keycloak.freemarker.Theme;
|
import org.keycloak.freemarker.Theme;
|
||||||
import org.keycloak.freemarker.ThemeLoader;
|
import org.keycloak.freemarker.ThemeLoader;
|
||||||
import org.keycloak.freemarker.ThemeProvider;
|
import org.keycloak.freemarker.ThemeProvider;
|
||||||
|
import org.keycloak.models.Config;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -14,13 +15,14 @@ import java.util.Set;
|
||||||
*/
|
*/
|
||||||
public class DefaultLoginThemeProvider implements ThemeProvider {
|
public class DefaultLoginThemeProvider implements ThemeProvider {
|
||||||
|
|
||||||
|
public static final String BASE = "base";
|
||||||
public static final String PATTERNFLY = "patternfly";
|
public static final String PATTERNFLY = "patternfly";
|
||||||
public static final String KEYCLOAK = "keycloak";
|
public static final String KEYCLOAK = "keycloak";
|
||||||
|
|
||||||
private static Set<String> defaultThemes = new HashSet<String>();
|
private static Set<String> defaultThemes = new HashSet<String>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
defaultThemes.add(ThemeLoader.BASE);
|
defaultThemes.add(BASE);
|
||||||
defaultThemes.add(PATTERNFLY);
|
defaultThemes.add(PATTERNFLY);
|
||||||
defaultThemes.add(KEYCLOAK);
|
defaultThemes.add(KEYCLOAK);
|
||||||
}
|
}
|
||||||
|
@ -33,7 +35,7 @@ public class DefaultLoginThemeProvider implements ThemeProvider {
|
||||||
@Override
|
@Override
|
||||||
public Theme createTheme(String name, Theme.Type type) throws IOException {
|
public Theme createTheme(String name, Theme.Type type) throws IOException {
|
||||||
if (hasTheme(name, type)) {
|
if (hasTheme(name, type)) {
|
||||||
return new ClassLoaderTheme(name, type);
|
return new ClassLoaderTheme(name, type, getClass().getClassLoader());
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package org.keycloak.theme;
|
||||||
|
|
||||||
import org.keycloak.freemarker.Theme;
|
import org.keycloak.freemarker.Theme;
|
||||||
import org.keycloak.freemarker.ThemeProvider;
|
import org.keycloak.freemarker.ThemeProvider;
|
||||||
|
import org.keycloak.models.Config;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileFilter;
|
import java.io.FileFilter;
|
||||||
|
@ -18,7 +19,7 @@ public class FolderThemeProvider implements ThemeProvider {
|
||||||
private File rootDir;
|
private File rootDir;
|
||||||
|
|
||||||
public FolderThemeProvider() {
|
public FolderThemeProvider() {
|
||||||
String d = System.getProperty("keycloak.theme.dir");
|
String d = Config.getThemeDir();
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
rootDir = new File(d);
|
rootDir = new File(d);
|
||||||
}
|
}
|
||||||
|
|
66
model/api/src/main/java/org/keycloak/models/Config.java
Normal file
66
model/api/src/main/java/org/keycloak/models/Config.java
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
package org.keycloak.models;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class Config {
|
||||||
|
|
||||||
|
public static final String ADMIN_REALM_KEY = "keycloak.admin.realm";
|
||||||
|
public static final String ADMIN_REALM_DEFAULT = "keycloak-admin";
|
||||||
|
|
||||||
|
public static final String MODEL_PROVIDER_KEY = "keycloak.model";
|
||||||
|
|
||||||
|
public static final String THEME_BASE_KEY = "keycloak.theme.base";
|
||||||
|
public static final String THEME_BASE_DEFAULT = "base";
|
||||||
|
public static final String THEME_DEFAULT_KEY = "keycloak.theme.default";
|
||||||
|
public static final String THEME_DEFAULT_DEFAULT = "keycloak";
|
||||||
|
public static final String THEME_DIR_KEY = "keycloak.theme.dir";
|
||||||
|
public static final String JBOSS_SERVER_CONFIG_DIR_KEY = "jboss.server.config.dir";
|
||||||
|
|
||||||
|
public static String getAdminRealm() {
|
||||||
|
return System.getProperty(ADMIN_REALM_KEY, ADMIN_REALM_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setAdminRealm(String realm) {
|
||||||
|
System.setProperty(ADMIN_REALM_KEY, realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getModelProvider() {
|
||||||
|
return System.getProperty(MODEL_PROVIDER_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setModelProvider(String provider) {
|
||||||
|
System.setProperty(MODEL_PROVIDER_KEY, provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getThemeDir() {
|
||||||
|
String themeDir = System.getProperty(THEME_DIR_KEY);
|
||||||
|
if (themeDir == null && System.getProperties().containsKey(JBOSS_SERVER_CONFIG_DIR_KEY)) {
|
||||||
|
themeDir = System.getProperty(JBOSS_SERVER_CONFIG_DIR_KEY) + File.separator + "themes";
|
||||||
|
}
|
||||||
|
return themeDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setThemeDir(String dir) {
|
||||||
|
System.setProperty(THEME_DIR_KEY, dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getThemeBase() {
|
||||||
|
return System.getProperty(THEME_BASE_KEY, THEME_BASE_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setThemeBase(String baseTheme) {
|
||||||
|
System.setProperty(THEME_BASE_KEY, baseTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getThemeDefault() {
|
||||||
|
return System.getProperty(THEME_DEFAULT_KEY, THEME_DEFAULT_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setThemeDefault(String defaultTheme) {
|
||||||
|
System.setProperty(THEME_DEFAULT_KEY, defaultTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -5,7 +5,6 @@ package org.keycloak.models;
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public interface Constants {
|
public interface Constants {
|
||||||
String ADMIN_REALM = "keycloak-admin";
|
|
||||||
String ADMIN_CONSOLE_APPLICATION = "admin-console";
|
String ADMIN_CONSOLE_APPLICATION = "admin-console";
|
||||||
|
|
||||||
String INTERNAL_ROLE = "KEYCLOAK_";
|
String INTERNAL_ROLE = "KEYCLOAK_";
|
||||||
|
@ -13,4 +12,5 @@ public interface Constants {
|
||||||
String ACCOUNT_MANAGEMENT_APP = "account";
|
String ACCOUNT_MANAGEMENT_APP = "account";
|
||||||
|
|
||||||
String INSTALLED_APP_URN = "urn:ietf:wg:oauth:2.0:oob";
|
String INSTALLED_APP_URN = "urn:ietf:wg:oauth:2.0:oob";
|
||||||
|
String INSTALLED_APP_URL = "http://localhost";
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package org.keycloak.models.utils;
|
||||||
|
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
|
|
||||||
|
import org.keycloak.models.Config;
|
||||||
import org.keycloak.models.ModelProvider;
|
import org.keycloak.models.ModelProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,7 +10,6 @@ import org.keycloak.models.ModelProvider;
|
||||||
*/
|
*/
|
||||||
public class ModelProviderUtils {
|
public class ModelProviderUtils {
|
||||||
|
|
||||||
public static final String MODEL_PROVIDER = "keycloak.model";
|
|
||||||
public static final String DEFAULT_MODEL_PROVIDER = "jpa";
|
public static final String DEFAULT_MODEL_PROVIDER = "jpa";
|
||||||
|
|
||||||
public static Iterable<ModelProvider> getRegisteredProviders() {
|
public static Iterable<ModelProvider> getRegisteredProviders() {
|
||||||
|
@ -17,7 +17,7 @@ public class ModelProviderUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ModelProvider getConfiguredModelProvider(Iterable<ModelProvider> providers) {
|
public static ModelProvider getConfiguredModelProvider(Iterable<ModelProvider> providers) {
|
||||||
String configuredProvider = System.getProperty(MODEL_PROVIDER);
|
String configuredProvider = Config.getModelProvider();
|
||||||
ModelProvider provider = null;
|
ModelProvider provider = null;
|
||||||
|
|
||||||
if (configuredProvider != null) {
|
if (configuredProvider != null) {
|
||||||
|
@ -46,5 +46,4 @@ public class ModelProviderUtils {
|
||||||
return getConfiguredModelProvider(getRegisteredProviders());
|
return getConfiguredModelProvider(getRegisteredProviders());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.keycloak.server;
|
package org.keycloak.server;
|
||||||
|
|
||||||
import org.jboss.resteasy.logging.Logger;
|
import org.jboss.resteasy.logging.Logger;
|
||||||
|
import org.keycloak.models.Config;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
@ -30,15 +31,6 @@ public class KeycloakServerApplication extends KeycloakApplication {
|
||||||
RealmRepresentation rep = loadJson(new FileInputStream(importRealm), RealmRepresentation.class);
|
RealmRepresentation rep = loadJson(new FileInputStream(importRealm), RealmRepresentation.class);
|
||||||
importRealm(session, rep);
|
importRealm(session, rep);
|
||||||
}
|
}
|
||||||
|
|
||||||
String themeDir = System.getProperty("keycloak.theme.dir");
|
|
||||||
if (themeDir == null) {
|
|
||||||
String jbossConfigDir = System.getProperty("jboss.server.config.dir");
|
|
||||||
if (jbossConfigDir != null) {
|
|
||||||
themeDir = jbossConfigDir + File.separator + "themes";
|
|
||||||
System.setProperty("keycloak.theme.dir", themeDir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void importRealm(KeycloakSession session, RealmRepresentation rep) {
|
public void importRealm(KeycloakSession session, RealmRepresentation rep) {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package org.keycloak.services.managers;
|
||||||
import org.jboss.resteasy.logging.Logger;
|
import org.jboss.resteasy.logging.Logger;
|
||||||
import org.keycloak.models.AdminRoles;
|
import org.keycloak.models.AdminRoles;
|
||||||
import org.keycloak.models.ApplicationModel;
|
import org.keycloak.models.ApplicationModel;
|
||||||
|
import org.keycloak.models.Config;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
|
@ -34,15 +35,17 @@ public class ApplianceBootstrap {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bootstrap(KeycloakSession session) {
|
public void bootstrap(KeycloakSession session) {
|
||||||
if (session.getRealm(Constants.ADMIN_REALM) != null) {
|
if (session.getRealm(Config.getAdminRealm()) != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info("Initializing " + Constants.ADMIN_REALM + " realm");
|
String adminRealmName = Config.getAdminRealm();
|
||||||
|
|
||||||
|
logger.info("Initializing " + adminRealmName + " realm");
|
||||||
|
|
||||||
RealmManager manager = new RealmManager(session);
|
RealmManager manager = new RealmManager(session);
|
||||||
RealmModel realm = manager.createRealm(Constants.ADMIN_REALM, Constants.ADMIN_REALM);
|
RealmModel realm = manager.createRealm(adminRealmName, adminRealmName);
|
||||||
realm.setName(Constants.ADMIN_REALM);
|
realm.setName(adminRealmName);
|
||||||
realm.setEnabled(true);
|
realm.setEnabled(true);
|
||||||
realm.addRequiredCredential(CredentialRepresentation.PASSWORD);
|
realm.addRequiredCredential(CredentialRepresentation.PASSWORD);
|
||||||
realm.setCentralLoginLifespan(3000);
|
realm.setCentralLoginLifespan(3000);
|
||||||
|
@ -54,9 +57,6 @@ public class ApplianceBootstrap {
|
||||||
realm.setRegistrationAllowed(false);
|
realm.setRegistrationAllowed(false);
|
||||||
manager.generateRealmKeys(realm);
|
manager.generateRealmKeys(realm);
|
||||||
|
|
||||||
realm.setLoginTheme("keycloak");
|
|
||||||
realm.setAccountTheme("keycloak");
|
|
||||||
|
|
||||||
ApplicationModel adminConsole = new ApplicationManager(manager).createApplication(realm, Constants.ADMIN_CONSOLE_APPLICATION);
|
ApplicationModel adminConsole = new ApplicationManager(manager).createApplication(realm, Constants.ADMIN_CONSOLE_APPLICATION);
|
||||||
adminConsole.setBaseUrl("/auth/admin/index.html");
|
adminConsole.setBaseUrl("/auth/admin/index.html");
|
||||||
adminConsole.setEnabled(true);
|
adminConsole.setEnabled(true);
|
||||||
|
|
|
@ -5,6 +5,7 @@ import org.keycloak.models.AccountRoles;
|
||||||
import org.keycloak.models.AdminRoles;
|
import org.keycloak.models.AdminRoles;
|
||||||
import org.keycloak.models.ApplicationModel;
|
import org.keycloak.models.ApplicationModel;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.models.Config;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.OAuthClientModel;
|
import org.keycloak.models.OAuthClientModel;
|
||||||
|
@ -51,7 +52,7 @@ public class RealmManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public RealmModel getKeycloakAdminstrationRealm() {
|
public RealmModel getKeycloakAdminstrationRealm() {
|
||||||
return getRealm(Constants.ADMIN_REALM);
|
return getRealm(Config.getAdminRealm());
|
||||||
}
|
}
|
||||||
|
|
||||||
public RealmModel getRealm(String id) {
|
public RealmModel getRealm(String id) {
|
||||||
|
@ -153,7 +154,7 @@ public class RealmManager {
|
||||||
RealmModel adminRealm;
|
RealmModel adminRealm;
|
||||||
RoleModel adminRole;
|
RoleModel adminRole;
|
||||||
|
|
||||||
if (realm.getName().equals(Constants.ADMIN_REALM)) {
|
if (realm.getName().equals(Config.getAdminRealm())) {
|
||||||
adminRealm = realm;
|
adminRealm = realm;
|
||||||
|
|
||||||
adminRole = realm.addRole(AdminRoles.ADMIN);
|
adminRole = realm.addRole(AdminRoles.ADMIN);
|
||||||
|
@ -161,7 +162,7 @@ public class RealmManager {
|
||||||
RoleModel createRealmRole = realm.addRole(AdminRoles.CREATE_REALM);
|
RoleModel createRealmRole = realm.addRole(AdminRoles.CREATE_REALM);
|
||||||
adminRole.addCompositeRole(createRealmRole);
|
adminRole.addCompositeRole(createRealmRole);
|
||||||
} else {
|
} else {
|
||||||
adminRealm = identitySession.getRealmByName(Constants.ADMIN_REALM);
|
adminRealm = identitySession.getRealmByName(Config.getAdminRealm());
|
||||||
adminRole = adminRealm.getRole(AdminRoles.ADMIN);
|
adminRole = adminRealm.getRole(AdminRoles.ADMIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,8 +51,6 @@ public class AccountService {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(AccountService.class);
|
private static final Logger logger = Logger.getLogger(AccountService.class);
|
||||||
|
|
||||||
public static final String ACCOUNT_IDENTITY_COOKIE = "KEYCLOAK_ACCOUNT_IDENTITY";
|
|
||||||
|
|
||||||
private RealmModel realm;
|
private RealmModel realm;
|
||||||
|
|
||||||
@Context
|
@Context
|
||||||
|
|
|
@ -8,6 +8,7 @@ import org.keycloak.OAuthErrorException;
|
||||||
import org.keycloak.jose.jws.JWSInput;
|
import org.keycloak.jose.jws.JWSInput;
|
||||||
import org.keycloak.jose.jws.crypto.RSAProvider;
|
import org.keycloak.jose.jws.crypto.RSAProvider;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakTransaction;
|
import org.keycloak.models.KeycloakTransaction;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
@ -619,7 +620,26 @@ public class TokenService {
|
||||||
return redirectUri;
|
return redirectUri;
|
||||||
} else {
|
} else {
|
||||||
String r = redirectUri.indexOf('?') != -1 ? redirectUri.substring(0, redirectUri.indexOf('?')) : redirectUri;
|
String r = redirectUri.indexOf('?') != -1 ? redirectUri.substring(0, redirectUri.indexOf('?')) : redirectUri;
|
||||||
return client.getRedirectUris().contains(r) ? redirectUri : null;
|
|
||||||
|
boolean valid = client.getRedirectUris().contains(r);
|
||||||
|
|
||||||
|
if (!valid && r.startsWith(Constants.INSTALLED_APP_URL) && r.indexOf(':', Constants.INSTALLED_APP_URL.length()) >= 0) {
|
||||||
|
int i = r.indexOf(':', Constants.INSTALLED_APP_URL.length());
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(r.substring(0, i));
|
||||||
|
|
||||||
|
i = r.indexOf('/', i);
|
||||||
|
if (i >= 0) {
|
||||||
|
sb.append(r.substring(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sb.toString();
|
||||||
|
|
||||||
|
valid = client.getRedirectUris().contains(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid ? redirectUri : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import org.jboss.resteasy.spi.HttpResponse;
|
||||||
import org.keycloak.jaxrs.JaxrsOAuthClient;
|
import org.keycloak.jaxrs.JaxrsOAuthClient;
|
||||||
import org.keycloak.models.AdminRoles;
|
import org.keycloak.models.AdminRoles;
|
||||||
import org.keycloak.models.ApplicationModel;
|
import org.keycloak.models.ApplicationModel;
|
||||||
|
import org.keycloak.models.Config;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
@ -84,6 +85,7 @@ public class AdminService {
|
||||||
|
|
||||||
public static class WhoAmI {
|
public static class WhoAmI {
|
||||||
protected String userId;
|
protected String userId;
|
||||||
|
protected String realm;
|
||||||
protected String displayName;
|
protected String displayName;
|
||||||
|
|
||||||
@JsonProperty("createRealm")
|
@JsonProperty("createRealm")
|
||||||
|
@ -94,8 +96,9 @@ public class AdminService {
|
||||||
public WhoAmI() {
|
public WhoAmI() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public WhoAmI(String userId, String displayName, boolean createRealm, Map<String, Set<String>> realmAccess) {
|
public WhoAmI(String userId, String realm, String displayName, boolean createRealm, Map<String, Set<String>> realmAccess) {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
|
this.realm = realm;
|
||||||
this.displayName = displayName;
|
this.displayName = displayName;
|
||||||
this.createRealm = createRealm;
|
this.createRealm = createRealm;
|
||||||
this.realmAccess = realmAccess;
|
this.realmAccess = realmAccess;
|
||||||
|
@ -109,6 +112,14 @@ public class AdminService {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getRealm() {
|
||||||
|
return realm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRealm(String realm) {
|
||||||
|
this.realm = realm;
|
||||||
|
}
|
||||||
|
|
||||||
public String getDisplayName() {
|
public String getDisplayName() {
|
||||||
return displayName;
|
return displayName;
|
||||||
}
|
}
|
||||||
|
@ -185,7 +196,7 @@ public class AdminService {
|
||||||
Map<String, Set<String>> realmAccess = new HashMap<String, Set<String>>();
|
Map<String, Set<String>> realmAccess = new HashMap<String, Set<String>>();
|
||||||
addRealmAdminAccess(realmAccess, auth.getRealm().getRoleMappings(auth.getUser()));
|
addRealmAdminAccess(realmAccess, auth.getRealm().getRoleMappings(auth.getUser()));
|
||||||
|
|
||||||
return Response.ok(new WhoAmI(user.getId(), displayName, createRealm, realmAccess)).build();
|
return Response.ok(new WhoAmI(user.getId(), Config.getAdminRealm(), displayName, createRealm, realmAccess)).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addRealmAdminAccess(Map<String, Set<String>> realmAdminAccess, Set<RoleModel> roles) {
|
private void addRealmAdminAccess(Map<String, Set<String>> realmAdminAccess, Set<RoleModel> roles) {
|
||||||
|
@ -283,7 +294,7 @@ public class AdminService {
|
||||||
expireCookie();
|
expireCookie();
|
||||||
|
|
||||||
JaxrsOAuthClient oauth = new JaxrsOAuthClient();
|
JaxrsOAuthClient oauth = new JaxrsOAuthClient();
|
||||||
String authUrl = TokenService.loginPageUrl(uriInfo).build(Constants.ADMIN_REALM).toString();
|
String authUrl = TokenService.loginPageUrl(uriInfo).build(Config.getAdminRealm()).toString();
|
||||||
logger.debug("authUrl: {0}", authUrl);
|
logger.debug("authUrl: {0}", authUrl);
|
||||||
oauth.setAuthUrl(authUrl);
|
oauth.setAuthUrl(authUrl);
|
||||||
oauth.setClientId(Constants.ADMIN_CONSOLE_APPLICATION);
|
oauth.setClientId(Constants.ADMIN_CONSOLE_APPLICATION);
|
||||||
|
@ -309,7 +320,7 @@ public class AdminService {
|
||||||
|
|
||||||
protected Response redirectOnLoginError(String message) {
|
protected Response redirectOnLoginError(String message) {
|
||||||
URI uri = uriInfo.getBaseUriBuilder().path(AdminService.class).path(AdminService.class, "errorOnLoginRedirect").queryParam("error", message).build();
|
URI uri = uriInfo.getBaseUriBuilder().path(AdminService.class).path(AdminService.class, "errorOnLoginRedirect").queryParam("error", message).build();
|
||||||
URI logout = TokenService.logoutUrl(uriInfo).queryParam("redirect_uri", uri.toString()).build(Constants.ADMIN_REALM);
|
URI logout = TokenService.logoutUrl(uriInfo).queryParam("redirect_uri", uri.toString()).build(Config.getAdminRealm());
|
||||||
return Response.status(302).location(logout).build();
|
return Response.status(302).location(logout).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ import io.undertow.servlet.api.ServletInfo;
|
||||||
import org.jboss.resteasy.logging.Logger;
|
import org.jboss.resteasy.logging.Logger;
|
||||||
import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer;
|
import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer;
|
||||||
import org.jboss.resteasy.spi.ResteasyDeployment;
|
import org.jboss.resteasy.spi.ResteasyDeployment;
|
||||||
|
import org.keycloak.models.Config;
|
||||||
import org.keycloak.theme.DefaultLoginThemeProvider;
|
import org.keycloak.theme.DefaultLoginThemeProvider;
|
||||||
import org.keycloak.services.tmp.TmpAdminRedirectServlet;
|
import org.keycloak.services.tmp.TmpAdminRedirectServlet;
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
@ -136,9 +137,9 @@ public class KeycloakServer {
|
||||||
throw new RuntimeException("Invalid resources directory");
|
throw new RuntimeException("Invalid resources directory");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!System.getProperties().containsKey("keycloak.theme.dir")) {
|
if (Config.getThemeDir() == null) {
|
||||||
System.setProperty(DefaultLoginThemeProvider.class.getName() + ".disabled", "");
|
System.setProperty(DefaultLoginThemeProvider.class.getName() + ".disabled", "");
|
||||||
System.setProperty("keycloak.theme.dir", file(dir.getAbsolutePath(), "forms", "common-themes", "src", "main", "resources", "theme").getAbsolutePath());
|
Config.setThemeDir(file(dir.getAbsolutePath(), "forms", "common-themes", "src", "main", "resources", "theme").getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
config.setResourcesHome(dir.getAbsolutePath());
|
config.setResourcesHome(dir.getAbsolutePath());
|
||||||
|
|
|
@ -96,11 +96,7 @@ public class AuthorizationCodeTest {
|
||||||
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
|
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
|
||||||
@Override
|
@Override
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||||
for (ApplicationModel app : appRealm.getApplications()) {
|
appRealm.getApplicationByName("test-app").addRedirectUri(oauth.getRedirectUri());
|
||||||
if (app.getName().equals("test-app")) {
|
|
||||||
app.addRedirectUri(oauth.getRedirectUri());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.junit.ClassRule;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.models.ApplicationModel;
|
import org.keycloak.models.ApplicationModel;
|
||||||
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.services.managers.RealmManager;
|
import org.keycloak.services.managers.RealmManager;
|
||||||
import org.keycloak.testsuite.OAuthClient;
|
import org.keycloak.testsuite.OAuthClient;
|
||||||
|
@ -49,6 +50,15 @@ public class OAuthRedirectUriTest {
|
||||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||||
ApplicationModel app = appRealm.getApplicationNameMap().get("test-app");
|
ApplicationModel app = appRealm.getApplicationNameMap().get("test-app");
|
||||||
app.addRedirectUri("http://localhost:8081/app");
|
app.addRedirectUri("http://localhost:8081/app");
|
||||||
|
|
||||||
|
ApplicationModel installedApp = appRealm.addApplication("test-installed");
|
||||||
|
installedApp.setEnabled(true);
|
||||||
|
installedApp.addRedirectUri(Constants.INSTALLED_APP_URN);
|
||||||
|
installedApp.addRedirectUri(Constants.INSTALLED_APP_URL);
|
||||||
|
|
||||||
|
ApplicationModel installedApp2 = appRealm.addApplication("test-installed2");
|
||||||
|
installedApp2.setEnabled(true);
|
||||||
|
installedApp2.addRedirectUri(Constants.INSTALLED_APP_URL + "/myapp");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -150,6 +160,15 @@ public class OAuthRedirectUriTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValid() throws IOException {
|
||||||
|
oauth.redirectUri("http://localhost:8081/app");
|
||||||
|
OAuthClient.AuthorizationCodeResponse response = oauth.doLogin("test-user@localhost", "password");
|
||||||
|
|
||||||
|
Assert.assertNotNull(response.getCode());
|
||||||
|
Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/app?code="));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInvalid() throws IOException {
|
public void testInvalid() throws IOException {
|
||||||
oauth.redirectUri("http://localhost:8081/app2");
|
oauth.redirectUri("http://localhost:8081/app2");
|
||||||
|
@ -168,4 +187,40 @@ public class OAuthRedirectUriTest {
|
||||||
Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/app?key=value&code="));
|
Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/app?key=value&code="));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLocalhost() throws IOException {
|
||||||
|
oauth.clientId("test-installed");
|
||||||
|
|
||||||
|
checkRedirectUri("urn:ietf:wg:oauth:2.0:oob", true);
|
||||||
|
checkRedirectUri("http://localhost", true);
|
||||||
|
|
||||||
|
checkRedirectUri("http://localhost:8081", true);
|
||||||
|
|
||||||
|
checkRedirectUri("http://localhosts", false);
|
||||||
|
checkRedirectUri("http://localhost/myapp", false);
|
||||||
|
checkRedirectUri("http://localhost:8081/myapp", false);
|
||||||
|
|
||||||
|
oauth.clientId("test-installed2");
|
||||||
|
|
||||||
|
checkRedirectUri("http://localhost/myapp", true);
|
||||||
|
checkRedirectUri("http://localhost:8081/myapp", true);
|
||||||
|
|
||||||
|
checkRedirectUri("http://localhosts/myapp", false);
|
||||||
|
checkRedirectUri("http://localhost", false);
|
||||||
|
checkRedirectUri("http://localhost/myapp2", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkRedirectUri(String redirectUri, boolean expectValid) {
|
||||||
|
oauth.redirectUri(redirectUri);
|
||||||
|
oauth.openLoginForm();
|
||||||
|
|
||||||
|
if (expectValid) {
|
||||||
|
Assert.assertTrue(loginPage.isCurrent());
|
||||||
|
} else {
|
||||||
|
Assert.assertTrue(errorPage.isCurrent());
|
||||||
|
Assert.assertEquals("Invalid redirect_uri.", errorPage.getError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package org.keycloak.testsuite.rule;
|
||||||
import io.undertow.servlet.api.DeploymentInfo;
|
import io.undertow.servlet.api.DeploymentInfo;
|
||||||
import io.undertow.servlet.api.ServletInfo;
|
import io.undertow.servlet.api.ServletInfo;
|
||||||
import org.junit.rules.ExternalResource;
|
import org.junit.rules.ExternalResource;
|
||||||
|
import org.keycloak.models.Config;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
@ -58,7 +59,7 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
|
||||||
try {
|
try {
|
||||||
RealmManager manager = new RealmManager(session);
|
RealmManager manager = new RealmManager(session);
|
||||||
|
|
||||||
RealmModel adminstrationRealm = manager.getRealm(Constants.ADMIN_REALM);
|
RealmModel adminstrationRealm = manager.getRealm(Config.getAdminRealm());
|
||||||
|
|
||||||
configure(manager, adminstrationRealm);
|
configure(manager, adminstrationRealm);
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
*/
|
*/
|
||||||
package org.keycloak.testsuite.rule;
|
package org.keycloak.testsuite.rule;
|
||||||
|
|
||||||
|
import org.keycloak.models.Config;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
@ -66,7 +67,7 @@ public class KeycloakRule extends AbstractKeycloakRule {
|
||||||
try {
|
try {
|
||||||
RealmManager manager = new RealmManager(session);
|
RealmManager manager = new RealmManager(session);
|
||||||
|
|
||||||
RealmModel adminstrationRealm = manager.getRealm(Constants.ADMIN_REALM);
|
RealmModel adminstrationRealm = manager.getRealm(Config.getAdminRealm());
|
||||||
RealmModel appRealm = manager.getRealm("test");
|
RealmModel appRealm = manager.getRealm("test");
|
||||||
|
|
||||||
configurer.config(manager, adminstrationRealm, appRealm);
|
configurer.config(manager, adminstrationRealm, appRealm);
|
||||||
|
|
Loading…
Reference in a new issue