keycloak-aplcache

Details

diff --git a/docbook/auth-server-docs/reference/en/en-US/modules/server-installation.xml b/docbook/auth-server-docs/reference/en/en-US/modules/server-installation.xml
index 01ad7e6..4dc4b32 100755
--- a/docbook/auth-server-docs/reference/en/en-US/modules/server-installation.xml
+++ b/docbook/auth-server-docs/reference/en/en-US/modules/server-installation.xml
@@ -130,15 +130,14 @@ cd <WILDFLY_HOME>/bin
         <section>
             <title>Admin User</title>
             <para>
-                To access the admin console you need an account to login. Currently, there's a default account added
-                with the username <literal>admin</literal> and password <literal>admin</literal>. You will be required
-                to change the password on first login. We are planning on removing the built-in account soon and will
-                instead have an initial step to create the user.
+                To access the admin console to configure Keycloak you need an account to login. There is no built in user,
+                instead you have to first create an admin account. This can done either by opening <ulink url="http://localhost:8080/auth">http://localhost:8080/auth</ulink>
+                (creating a user through the browser can only be done through localhost) or you can use the add-user script from
+                the command-line.
             </para>
             <para>
-                You can also create a user with the <literal>add-user</literal> script found in <literal>bin</literal>.
-                This script will create a temporary file with the details of the user, which are imported at startup.
-                To add a user with this script run:
+                The <literal>add-user</literal> script creates a temporary file with the details of the user,
+                which are imported at startup. To add a user with this script run:
 <programlisting><![CDATA[
 bin/add-user.[sh|bat] -r master -u <username> -p <password>
 ]]></programlisting>
diff --git a/services/src/main/java/org/keycloak/exportimport/ExportImportManager.java b/services/src/main/java/org/keycloak/exportimport/ExportImportManager.java
index cedcbdd..4f94b52 100644
--- a/services/src/main/java/org/keycloak/exportimport/ExportImportManager.java
+++ b/services/src/main/java/org/keycloak/exportimport/ExportImportManager.java
@@ -2,10 +2,9 @@ package org.keycloak.exportimport;
 
 
 import org.jboss.logging.Logger;
-import org.keycloak.Config;
 import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
-import org.keycloak.services.managers.ApplianceBootstrap;
+
+import java.io.IOException;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -14,76 +13,82 @@ public class ExportImportManager {
 
     private static final Logger logger = Logger.getLogger(ExportImportManager.class);
 
-    public void checkExportImport(KeycloakSessionFactory sessionFactory, String contextPath) {
+    private KeycloakSession session;
+
+    private final String realmName;
+
+    private ExportProvider exportProvider;
+    private ImportProvider importProvider;
+
+    public ExportImportManager(KeycloakSession session) {
+        this.session = session;
+
+        realmName = ExportImportConfig.getRealmName();
+
+        String providerId = ExportImportConfig.getProvider();
         String exportImportAction = ExportImportConfig.getAction();
-        String realmName = ExportImportConfig.getRealmName();
 
-        boolean export = false;
-        boolean importt = false;
         if (ExportImportConfig.ACTION_EXPORT.equals(exportImportAction)) {
-            export = true;
+            exportProvider = session.getProvider(ExportProvider.class, providerId);
+            if (exportProvider == null) {
+                throw new RuntimeException("Export provider not found");
+            }
         } else if (ExportImportConfig.ACTION_IMPORT.equals(exportImportAction)) {
-            importt = true;
+            importProvider = session.getProvider(ImportProvider.class, providerId);
+            if (importProvider == null) {
+                throw new RuntimeException("Import provider not found");
+            }
+        }
+    }
+
+    public boolean isRunImport() {
+        return importProvider != null;
+    }
+
+    public boolean isImportMasterIncluded() {
+        if (!isRunImport()) {
+            throw new IllegalStateException("Import not enabled");
+        }
+        try {
+            return importProvider.isMasterRealmExported();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
         }
+    }
+
+    public boolean isRunExport() {
+        return exportProvider != null;
+    }
 
-        if (export || importt) {
-            String exportImportProviderId = ExportImportConfig.getProvider();
-            logger.debug("Will use provider: " + exportImportProviderId);
-            KeycloakSession session = sessionFactory.create();
-
-            try {
-                if (export) {
-                    ExportProvider exportProvider = session.getProvider(ExportProvider.class, exportImportProviderId);
-
-                    if (exportProvider == null) {
-                        logger.errorf("Invalid Export Provider %s", exportImportProviderId);
-                    } else {
-                        if (realmName == null) {
-                            logger.info("Full model export requested");
-                            exportProvider.exportModel(sessionFactory);
-                        } else {
-                            logger.infof("Export of realm '%s' requested", realmName);
-                            exportProvider.exportRealm(sessionFactory, realmName);
-                        }
-                        logger.info("Export finished successfully");
-                    }
-                } else {
-                    ImportProvider importProvider = session.getProvider(ImportProvider.class, exportImportProviderId);
-                    
-                    if (importProvider == null) {
-                    	logger.errorf("Invalid Import Provider %s", exportImportProviderId);
-                    } else {
-                    
-	                    Strategy strategy = ExportImportConfig.getStrategy();
-	                    if (realmName == null) {
-	                        logger.infof("Full model import requested. Strategy: %s", strategy.toString());
-	                        
-	                        // Check if master realm was exported. If it's not, then it needs to be created before other realms are imported
-	                        if (!importProvider.isMasterRealmExported()) {
-	                            ApplianceBootstrap.setupDefaultRealm(sessionFactory, contextPath);
-                                ApplianceBootstrap.setupDefaultUser(sessionFactory);
-	                        }
-	
-	                        importProvider.importModel(sessionFactory, strategy);
-	                    } else {
-	                        logger.infof("Import of realm '%s' requested. Strategy: %s", realmName, strategy.toString());
-	
-	                        if (!realmName.equals(Config.getAdminRealm())) {
-	                            // Check if master realm exists. If it's not, then it needs to be created before other realm is imported
-                                ApplianceBootstrap.setupDefaultRealm(sessionFactory, contextPath);
-                                ApplianceBootstrap.setupDefaultUser(sessionFactory);
-	                        }
-	
-	                        importProvider.importRealm(sessionFactory, realmName, strategy);
-	                    }
-	                    logger.info("Import finished successfully");
-                    }
-                }
-            } catch (Throwable ioe) {
-                logger.error("Error during export/import", ioe);
-            } finally {
-                session.close();
+    public void runImport() {
+        try {
+            Strategy strategy = ExportImportConfig.getStrategy();
+            if (realmName == null) {
+                logger.infof("Full model import requested. Strategy: %s", strategy.toString());
+                importProvider.importModel(session.getKeycloakSessionFactory(), strategy);
+            } else {
+                logger.infof("Import of realm '%s' requested. Strategy: %s", realmName, strategy.toString());
+                importProvider.importRealm(session.getKeycloakSessionFactory(), realmName, strategy);
             }
+            logger.info("Import finished successfully");
+        } catch (IOException e) {
+            throw new RuntimeException("Failed to run import", e);
         }
     }
+
+    public void runExport() {
+        try {
+            if (realmName == null) {
+                logger.info("Full model export requested");
+                exportProvider.exportModel(session.getKeycloakSessionFactory());
+            } else {
+                logger.infof("Export of realm '%s' requested", realmName);
+                exportProvider.exportRealm(session.getKeycloakSessionFactory(), realmName);
+            }
+            logger.info("Export finished successfully");
+        } catch (IOException e) {
+            throw new RuntimeException("Failed to run export");
+        }
+    }
+
 }
diff --git a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
index 8402016..829dd6c 100755
--- a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
+++ b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
@@ -4,15 +4,7 @@ import org.jboss.logging.Logger;
 import org.keycloak.Config;
 import org.keycloak.common.Version;
 import org.keycloak.common.enums.SslRequired;
-import org.keycloak.models.AdminRoles;
-import org.keycloak.models.ClientModel;
-import org.keycloak.models.Constants;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.RoleModel;
-import org.keycloak.models.UserCredentialModel;
-import org.keycloak.models.UserModel;
+import org.keycloak.models.*;
 import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.representations.idm.CredentialRepresentation;
 
@@ -23,17 +15,34 @@ import org.keycloak.representations.idm.CredentialRepresentation;
 public class ApplianceBootstrap {
 
     private static final Logger logger = Logger.getLogger(ApplianceBootstrap.class);
+    private final KeycloakSession session;
 
-    public static boolean setupDefaultRealm(KeycloakSessionFactory sessionFactory, String contextPath) {
-        KeycloakSession session = sessionFactory.create();
-        session.getTransaction().begin();
+    public ApplianceBootstrap(KeycloakSession session) {
+        this.session = session;
+    }
+
+    public boolean isNewInstall() {
+        if (session.realms().getRealms().size() > 0) {
+            return false;
+        } else {
+            return true;
+        }
+    }
 
+    public boolean isNoMasterUser() {
+        RealmModel realm = session.realms().getRealm(Config.getAdminRealm());
+        return session.users().getUsersCount(realm) == 0;
+    }
+
+    public boolean createMasterRealm(String contextPath) {
+        if (!isNewInstall()) {
+            throw new IllegalStateException("Can't create default realm as realms already exists");
+        }
+
+        KeycloakSession session = this.session.getKeycloakSessionFactory().create();
         try {
+            session.getTransaction().begin();
             String adminRealmName = Config.getAdminRealm();
-            if (session.realms().getRealm(adminRealmName) != null) {
-                return false;
-            }
-
             logger.info("Initializing " + adminRealmName + " realm");
 
             RealmManager manager = new RealmManager(session);
@@ -58,41 +67,29 @@ public class ApplianceBootstrap {
             KeycloakModelUtils.generateRealmKeys(realm);
 
             session.getTransaction().commit();
-            return true;
         } finally {
             session.close();
         }
-    }
 
-    public static boolean setupDefaultUser(KeycloakSessionFactory sessionFactory) {
-        KeycloakSession session = sessionFactory.create();
-        session.getTransaction().begin();
+        return true;
+    }
 
-        try {
-            RealmModel realm = session.realms().getRealm(Config.getAdminRealm());
-            if (session.users().getUserByUsername("admin", realm) == null) {
-                UserModel adminUser = session.users().addUser(realm, "admin");
-
-                adminUser.setEnabled(true);
-                UserCredentialModel usrCredModel = new UserCredentialModel();
-                usrCredModel.setType(UserCredentialModel.PASSWORD);
-                usrCredModel.setValue("admin");
-                session.users().updateCredential(realm, adminUser, usrCredModel);
-                adminUser.addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
-
-                RoleModel adminRole = realm.getRole(AdminRoles.ADMIN);
-                adminUser.grantRole(adminRole);
-
-                ClientModel accountApp = realm.getClientNameMap().get(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID);
-                for (String r : accountApp.getDefaultRoles()) {
-                    adminUser.grantRole(accountApp.getRole(r));
-                }
-            }
-            session.getTransaction().commit();
-            return true;
-        } finally {
-            session.close();
+    public void createMasterRealmUser(KeycloakSession session, String username, String password) {
+        RealmModel realm = session.realms().getRealm(Config.getAdminRealm());
+        if (session.users().getUsersCount(realm) > 0) {
+            throw new IllegalStateException("Can't create initial user as users already exists");
         }
+
+        UserModel adminUser = session.users().addUser(realm, username);
+        adminUser.setEnabled(true);
+
+        UserCredentialModel usrCredModel = new UserCredentialModel();
+        usrCredModel.setType(UserCredentialModel.PASSWORD);
+        usrCredModel.setValue(password);
+        session.users().updateCredential(realm, adminUser, usrCredModel);
+
+        RoleModel adminRole = realm.getRole(AdminRoles.ADMIN);
+        adminUser.grantRole(adminRole);
     }
 
 }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java
index 5c22200..50e33dd 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminConsole.java
@@ -264,10 +264,7 @@ public class AdminConsole {
         if (!uriInfo.getRequestUri().getPath().endsWith("/")) {
             return Response.status(302).location(uriInfo.getRequestUriBuilder().path("/").build()).build();
         } else {
-            String adminTheme = realm.getAdminTheme();
-            if (adminTheme == null) {
-                adminTheme = "keycloak";
-            }
+            Theme theme = getTheme();
 
             Map<String, Object> map = new HashMap<>();
 
@@ -277,11 +274,8 @@ public class AdminConsole {
             authUrl = authUrl.substring(0, authUrl.length() - 1);
 
             map.put("authUrl", authUrl);
-            map.put("resourceUrl", Urls.themeRoot(baseUri) + "/admin/" + adminTheme);
+            map.put("resourceUrl", Urls.themeRoot(baseUri) + "/admin/" + theme.getName());
             map.put("resourceVersion", Version.RESOURCES_VERSION);
-
-            Theme theme = getTheme();
-
             map.put("properties", theme.getProperties());
 
             FreeMarkerUtil freeMarkerUtil = new FreeMarkerUtil();
diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
index 88569b6..2d49464 100755
--- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -74,24 +74,51 @@ public class KeycloakApplication extends Application {
         classes.add(QRCodeResource.class);
         classes.add(ThemeResource.class);
         classes.add(JsResource.class);
-        classes.add(WelcomeResource.class);
 
         singletons.add(new ObjectMapperResolver(Boolean.parseBoolean(System.getProperty("keycloak.jsonPrettyPrint", "false"))));
 
-        boolean defaultRealmCreated = ApplianceBootstrap.setupDefaultRealm(sessionFactory, context.getContextPath());
-
         migrateModel();
         sessionFactory.publish(new PostMigrationEvent());
 
-        new ExportImportManager().checkExportImport(this.sessionFactory, context.getContextPath());
-        importRealms(context);
+        boolean bootstrapAdminUser = false;
+
+        KeycloakSession session = sessionFactory.create();
+        try {
+            session.getTransaction().begin();
+
+            ApplianceBootstrap applianceBootstrap = new ApplianceBootstrap(session);
+            ExportImportManager exportImportManager = new ExportImportManager(session);
+
+            boolean createMasterRealm = applianceBootstrap.isNewInstall();
+            if (exportImportManager.isRunImport() && exportImportManager.isImportMasterIncluded()) {
+                createMasterRealm = false;
+            }
+
+            if (createMasterRealm) {
+                applianceBootstrap.createMasterRealm(contextPath);
+            }
+
+            if (exportImportManager.isRunImport()) {
+                exportImportManager.runImport();
+            } else {
+                importRealms();
+            }
+
+            importAddUser();
 
-        importAddUser();
+            if (exportImportManager.isRunExport()) {
+                exportImportManager.runExport();
+            }
+
+            bootstrapAdminUser = applianceBootstrap.isNoMasterUser();
 
-        if (defaultRealmCreated) {
-            ApplianceBootstrap.setupDefaultUser(sessionFactory);
+            session.getTransaction().commit();
+        } finally {
+            session.close();
         }
 
+        singletons.add(new WelcomeResource(bootstrapAdminUser));
+
         setupScheduledTasks(sessionFactory);
     }
 
@@ -185,34 +212,13 @@ public class KeycloakApplication extends Application {
         return singletons;
     }
 
-    public void importRealms(ServletContext context) {
-        importRealmFile();
-        importRealmResources(context);
-    }
-
-    public void importRealmResources(ServletContext context) {
-        String resources = context.getInitParameter("keycloak.import.realm.resources");
-        if (resources != null) {
-            StringTokenizer tokenizer = new StringTokenizer(resources, ",");
-            while (tokenizer.hasMoreTokens()) {
-                String resource = tokenizer.nextToken().trim();
-                InputStream is = context.getResourceAsStream(resource);
-                if (is == null) {
-                    log.warn("Could not find realm resource to import: " + resource);
-                }
-                RealmRepresentation rep = loadJson(is, RealmRepresentation.class);
-                importRealm(rep, "resource " + resource);
-            }
-        }
-    }
-
-    public void importRealmFile() {
+    public void importRealms() {
         String files = System.getProperty("keycloak.import");
         if (files != null) {
             StringTokenizer tokenizer = new StringTokenizer(files, ",");
             while (tokenizer.hasMoreTokens()) {
                 String file = tokenizer.nextToken().trim();
-                RealmRepresentation rep = null;
+                RealmRepresentation rep;
                 try {
                     rep = loadJson(new FileInputStream(file), RealmRepresentation.class);
                 } catch (FileNotFoundException e) {
diff --git a/services/src/main/java/org/keycloak/services/resources/WelcomeResource.java b/services/src/main/java/org/keycloak/services/resources/WelcomeResource.java
index 7aa6b01..e778de3 100755
--- a/services/src/main/java/org/keycloak/services/resources/WelcomeResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/WelcomeResource.java
@@ -2,22 +2,24 @@ package org.keycloak.services.resources;
 
 import org.jboss.logging.Logger;
 import org.keycloak.Config;
+import org.keycloak.freemarker.FreeMarkerUtil;
 import org.keycloak.freemarker.Theme;
 import org.keycloak.freemarker.ThemeProvider;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.common.util.MimeTypeUtil;
+import org.keycloak.services.managers.ApplianceBootstrap;
+import org.keycloak.services.util.CacheControlUtil;
 
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.CacheControl;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.*;
+import javax.ws.rs.core.*;
+import java.io.IOException;
 import java.io.InputStream;
+import java.net.InetAddress;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -27,12 +29,18 @@ public class WelcomeResource {
 
     private static final Logger logger = Logger.getLogger(WelcomeResource.class);
 
+    private boolean bootstrap;
+
     @Context
     private UriInfo uriInfo;
 
     @Context
     protected KeycloakSession session;
 
+    public WelcomeResource(boolean bootstrap) {
+        this.bootstrap = bootstrap;
+    }
+
     /**
      * Welcome page of Keycloak
      *
@@ -42,11 +50,56 @@ public class WelcomeResource {
     @GET
     @Produces("text/html")
     public Response getWelcomePage() throws URISyntaxException {
+        checkBootstrap();
+
         String requestUri = uriInfo.getRequestUri().toString();
         if (!requestUri.endsWith("/")) {
             return Response.seeOther(new URI(requestUri + "/")).build();
         } else {
-            return getResource("index.html");
+            return createWelcomePage(null, null);
+        }
+    }
+
+    @POST
+    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+    public Response createUser(final MultivaluedMap<String, String> formData) {
+        checkBootstrap();
+
+        if (!bootstrap) {
+            return createWelcomePage(null, null);
+        } else {
+            if (!isLocal()) {
+                logger.errorv("Rejected non-local attempt to create initial user from {0}", session.getContext().getConnection().getRemoteAddr());
+                throw new WebApplicationException(Response.Status.BAD_REQUEST);
+            }
+
+            String username = formData.getFirst("username");
+            String password = formData.getFirst("password");
+            String passwordConfirmation = formData.getFirst("passwordConfirmation");
+
+            if (username == null || username.length() == 0) {
+                return createWelcomePage(null, "Username is missing");
+            }
+
+            if (password == null || password.length() == 0) {
+                return createWelcomePage(null, "Password is missing");
+            }
+
+            if (!password.equals(passwordConfirmation)) {
+                return createWelcomePage(null, "Password and confirmation doesn't match");
+            }
+
+            ApplianceBootstrap applianceBootstrap = new ApplianceBootstrap(session);
+            if (applianceBootstrap.isNoMasterUser()) {
+                bootstrap = false;
+                applianceBootstrap.createMasterRealmUser(session, username, password);
+
+                logger.infov("Created initial admin user with username {0}", username);
+                return createWelcomePage("User created", null);
+            } else {
+                logger.warnv("Rejected attempt to create initial user as user is already created");
+                return createWelcomePage(null, "Users already exists");
+            }
         }
     }
 
@@ -61,26 +114,62 @@ public class WelcomeResource {
     @Produces("text/html")
     public Response getResource(@PathParam("path") String path) {
         try {
-            Config.Scope config = Config.scope("theme");
-
-            ThemeProvider themeProvider = session.getProvider(ThemeProvider.class, "extending");
-            Theme theme = themeProvider.getTheme(config.get("welcomeTheme"), Theme.Type.WELCOME);
-            InputStream resource = theme.getResourceAsStream(path);
+            InputStream resource = getTheme().getResourceAsStream(path);
             if (resource != null) {
                 String contentType = MimeTypeUtil.getContentType(path);
-
-                CacheControl cacheControl = new CacheControl();
-                cacheControl.setNoTransform(false);
-                cacheControl.setMaxAge(config.getInt("staticMaxAge", -1));
-
-                Response.ResponseBuilder builder = Response.ok(resource).type(contentType).cacheControl(cacheControl);
+                Response.ResponseBuilder builder = Response.ok(resource).type(contentType).cacheControl(CacheControlUtil.getDefaultCacheControl());
                 return builder.build();
             } else {
                 return Response.status(Response.Status.NOT_FOUND).build();
             }
+        } catch (IOException e) {
+            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
+        }
+    }
+
+    private Response createWelcomePage(String successMessage, String errorMessage) {
+        try {
+            Map<String, Object> map = new HashMap<>();
+            map.put("bootstrap", bootstrap);
+            if (bootstrap) {
+                map.put("localUser", isLocal());
+            }
+            if (successMessage != null) {
+                map.put("successMessage", successMessage);
+            }
+            if (errorMessage != null) {
+                map.put("errorMessage", errorMessage);
+            }
+            FreeMarkerUtil freeMarkerUtil = new FreeMarkerUtil();
+            String result = freeMarkerUtil.processTemplate(map, "index.ftl", getTheme());
+            return Response.status(errorMessage == null ? Response.Status.OK : Response.Status.BAD_REQUEST).entity(result).cacheControl(CacheControlUtil.noCache()).build();
         } catch (Exception e) {
-            logger.warn("Failed to get theme resource", e);
-            return Response.serverError().build();
+            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
+        }
+    }
+
+    private Theme getTheme() {
+        Config.Scope config = Config.scope("theme");
+        ThemeProvider themeProvider = session.getProvider(ThemeProvider.class, "extending");
+        try {
+            return themeProvider.getTheme(config.get("welcomeTheme"), Theme.Type.WELCOME);
+        } catch (IOException e) {
+            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
+        }
+    }
+
+    private void checkBootstrap() {
+        if (bootstrap) {
+            bootstrap  = new ApplianceBootstrap(session).isNoMasterUser();
+        }
+    }
+
+    private boolean isLocal() {
+        try {
+            InetAddress inetAddress = InetAddress.getByName(session.getContext().getConnection().getRemoteAddr());
+            return inetAddress.isAnyLocalAddress() || inetAddress.isLoopbackAddress();
+        } catch (UnknownHostException e) {
+            throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
         }
     }
 
diff --git a/services/src/main/java/org/keycloak/services/util/CacheControlUtil.java b/services/src/main/java/org/keycloak/services/util/CacheControlUtil.java
index 259083a..0e2f1e0 100644
--- a/services/src/main/java/org/keycloak/services/util/CacheControlUtil.java
+++ b/services/src/main/java/org/keycloak/services/util/CacheControlUtil.java
@@ -19,7 +19,12 @@ public class CacheControlUtil {
             cacheControl.setNoCache(true);
         }
         return cacheControl;
+    }
 
+    public static CacheControl noCache() {
+        CacheControl cacheControl = new CacheControl();
+        cacheControl.setNoCache(true);
+        return cacheControl;
     }
 
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/KeycloakServer.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/KeycloakServer.java
index 28f0915..2466f36 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/KeycloakServer.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/KeycloakServer.java
@@ -33,10 +33,10 @@ import org.jboss.resteasy.spi.ResteasyDeployment;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.models.RealmModel;
-import org.keycloak.models.UserModel;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.services.filters.ClientConnectionFilter;
 import org.keycloak.services.filters.KeycloakSessionServletFilter;
+import org.keycloak.services.managers.ApplianceBootstrap;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.services.resources.KeycloakApplication;
 import org.keycloak.util.JsonSerialization;
@@ -273,19 +273,17 @@ public class KeycloakServer {
     }
 
     protected void setupDevConfig() {
-        KeycloakSession session = sessionFactory.create();
-        session.getTransaction().begin();
-
-        try {
-            RealmManager manager = new RealmManager(session);
-
-            RealmModel adminRealm = manager.getKeycloakAdminstrationRealm();
-            UserModel admin = session.users().getUserByUsername("admin", adminRealm);
-            admin.removeRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
-
-            session.getTransaction().commit();
-        } finally {
-            session.close();
+        if (System.getProperty("keycloak.createAdminUser", "true").equals("true")) {
+            KeycloakSession session = sessionFactory.create();
+            try {
+                session.getTransaction().begin();
+                if (new ApplianceBootstrap(session).isNoMasterUser()) {
+                    new ApplianceBootstrap(session).createMasterRealmUser(session, "admin", "admin");
+                }
+                session.getTransaction().commit();
+            } finally {
+                session.close();
+            }
         }
     }
 
@@ -311,7 +309,6 @@ public class KeycloakServer {
             di.setDefaultEncoding("UTF-8");
 
             di.setDefaultServletConfig(new DefaultServletConfig(true));
-            di.addWelcomePage("theme/keycloak/welcome/resources/index.html");
 
             FilterInfo filter = Servlets.filter("SessionFilter", KeycloakSessionServletFilter.class);
             di.addFilter(filter);
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/WelcomePage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/WelcomePage.java
new file mode 100644
index 0000000..3adbbac
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/WelcomePage.java
@@ -0,0 +1,44 @@
+package org.keycloak.testsuite.auth.page;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class WelcomePage extends AuthServer {
+
+    @FindBy(id = "username")
+    private WebElement usernameInput;
+
+    @FindBy(id = "password")
+    private WebElement passwordInput;
+
+    @FindBy(id = "passwordConfirmation")
+    private WebElement passwordConfirmationInput;
+
+    @FindBy(id = "create-button")
+    private WebElement createButton;
+
+    public boolean isPasswordSet() {
+        return !driver.getPageSource().contains("Please create an initial admin user to get started.");
+    }
+
+    public void setPassword(String username, String password) {
+        usernameInput.clear();
+        usernameInput.sendKeys(username);
+
+        passwordInput.clear();
+        passwordInput.sendKeys(password);
+
+        passwordConfirmationInput.clear();
+        passwordConfirmationInput.sendKeys(password);
+
+        createButton.click();
+
+        if (!driver.getPageSource().contains("User created")) {
+            throw new RuntimeException("Failed to updated password");
+        }
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
index 063347a..13ec96e 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
@@ -20,6 +20,7 @@ import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 import static org.keycloak.testsuite.admin.Users.setPasswordFor;
 import org.keycloak.testsuite.arquillian.SuiteContext;
+import org.keycloak.testsuite.auth.page.WelcomePage;
 import org.keycloak.testsuite.util.OAuthClient;
 import org.openqa.selenium.WebDriver;
 import org.keycloak.testsuite.auth.page.AuthServer;
@@ -76,6 +77,9 @@ public abstract class AbstractKeycloakTest {
     @Page
     protected UpdatePassword updatePasswordPage;
 
+    @Page
+    protected WelcomePage welcomePage;
+
     protected UserRepresentation adminUser;
 
     @Before
@@ -103,11 +107,10 @@ public abstract class AbstractKeycloakTest {
     }
 
     private void updateMasterAdminPassword() {
-        accountPage.navigateTo();
-        loginPage.form().login(ADMIN, ADMIN);
-        updatePasswordPage.updatePasswords(ADMIN, ADMIN);
-        assertCurrentUrlStartsWith(accountPage);
-        deleteAllCookiesForMasterRealm();
+        welcomePage.navigateTo();
+        if (!welcomePage.isPasswordSet()) {
+            welcomePage.setPassword("admin", "admin");
+        }
     }
 
     public void deleteAllCookiesForMasterRealm() {