Merge pull request #377 from patriot1burke/master

aerogear template
This commit is contained in:
Bill Burke 2014-05-12 19:40:00 -04:00
commit 634f61281d
21 changed files with 223 additions and 53 deletions

View file

@ -12,25 +12,29 @@ import java.util.Properties;
*/ */
public class ClassLoaderTheme implements Theme { public class ClassLoaderTheme implements Theme {
private final String name; private String name;
private final String parentName; private String parentName;
private final String importName; private String importName;
private final Type type; private Type type;
private final ClassLoader classLoader; private ClassLoader classLoader;
private final String templateRoot; private String templateRoot;
private final String resourceRoot; private String resourceRoot;
private final String messages; private String messages;
private final Properties properties; private Properties properties;
public ClassLoaderTheme(String name, Type type, ClassLoader classLoader) throws IOException { public ClassLoaderTheme(String name, Type type, ClassLoader classLoader) throws IOException {
init(name, type, classLoader);
}
public void init(String name, Type type, ClassLoader classLoader) throws IOException {
this.name = name; this.name = name;
this.type = type; this.type = type;
this.classLoader = classLoader; this.classLoader = classLoader;
@ -53,6 +57,10 @@ public class ClassLoaderTheme implements Theme {
} }
} }
public ClassLoaderTheme() {
}
@Override @Override
public String getName() { public String getName() {
return name; return name;

View file

@ -31,4 +31,5 @@
border-bottom: none; border-bottom: none;
border-right-color: rgba(255,255,255,0.15); border-right-color: rgba(255,255,255,0.15);
border-top-color: rgba(255,255,255,0.05); border-top-color: rgba(255,255,255,0.05);
} }

View file

@ -2,14 +2,30 @@ Self Bootstrapping Keycloak Server and Application
========================================================== ==========================================================
This is an example of bundling two wars: a keycloak server war and application WAR together so that keycloak is bootstrapped out of the This is an example of bundling two wars: a keycloak server war and application WAR together so that keycloak is bootstrapped out of the
box. box. The structure of the example is:
* The aerogear UPS application [http://localhost:8080/aerogear-ups/ups/view.jsp](http://localhost:8080/aerogear-ups/ups/view.jsp)
* The aerogear UPS admin [http://localhost:8080/aerogear-ups/admin/admin.html](http://localhost:8080/aerogear-ups/admin/admin.html)
* The aerogear security admin (keycloak) [http://localhost:8080/auth/admin/aerogear/console/index.html](http://localhost:8080/auth/admin/aerogear/console/index.html)
* The aerogear user account page (keycloak) [http://localhost:8080/auth/realms/aerogear/account](http://localhost:8080/auth/realms/aerogear/account)
* All of these are managed under one realm "aerogear"
* The login page, admin console, and account pages all use the "aerogear" theme
If you click on any of those URLS, you are brought to a log-in screen. Username: admin Password: admin. You will be asked
to change your password. Once you are logged in, you have SSO to any of those links.
Notes on implementation:
* There is a testrealm.json file that is used to bootstrap the realm in the auth-server/ project * There is a testrealm.json file that is used to bootstrap the realm in the auth-server/ project
* Notice that there is a context-param in auth-server/web.xml called keycloak.import.realm.resources. This sets up the import of the json file * Notice that there is a context-param in auth-server/web.xml called keycloak.import.realm.resources. This sets up the import of the json file
* If you open up testrealm.json, notice that all urls are relative. Keycloak will now extrapolate the host and port based * If you open up testrealm.json, notice that all urls are relative. Keycloak will now extrapolate the host and port based
on the request if the configured urls are just a path and don't have a schem, host, and port. on the request if the configured urls are just a path and don't have a schem, host, and port.
* In the auth project, there is a AerogearThemeProvider class. This sets up classloader access to the "aerogear" themes
* In the auth project, there is a UpsSecurityApplication class. The sole purpose of this class is to disable the "master"
realm by deleting the master realm's "admin" user
* In the auth project resources/, there are files there to set up all the themes
* In app, there is a BootstrapListener class. This obtains the config context of the adapter and initializes it. * In app, there is a BootstrapListener class. This obtains the config context of the adapter and initializes it.
* Notice that this class sets up a relative URL. Also notice that the application is a "public" client. This is so that * Notice that BootstrapListener class sets up a relative URL. Also notice that the application is a "public" client. This is so that
we don't have to query the database for the application's secret. Also notice that the realm key is not set. Keycloak adapter we don't have to query the database for the application's secret. Also notice that the realm key is not set. Keycloak adapter
will now query the auth server url for the public key of the realm. will now query the auth server url for the public key of the realm.

View file

@ -85,7 +85,7 @@
</dependencies> </dependencies>
<build> <build>
<finalName>app</finalName> <finalName>aerogear-ups</finalName>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.jboss.as.plugins</groupId> <groupId>org.jboss.as.plugins</groupId>

View file

@ -15,8 +15,8 @@ public class BootstrapListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) { public void contextInitialized(ServletContextEvent sce) {
AdapterDeploymentContext deploymentContext = (AdapterDeploymentContext)sce.getServletContext().getAttribute(AdapterDeploymentContext.class.getName()); AdapterDeploymentContext deploymentContext = (AdapterDeploymentContext)sce.getServletContext().getAttribute(AdapterDeploymentContext.class.getName());
AdapterConfig config = new AdapterConfig(); AdapterConfig config = new AdapterConfig();
config.setRealm("demo"); config.setRealm("aerogear");
config.setResource("customer-portal"); config.setResource("unified-push-server");
config.setAuthServerUrl("/auth"); config.setAuthServerUrl("/auth");
config.setSslNotRequired(true); config.setSslNotRequired(true);
config.setPublicClient(true); config.setPublicClient(true);

View file

@ -4,7 +4,7 @@
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"> version="3.0">
<module-name>app</module-name> <module-name>aerogear-ups</module-name>
<listener> <listener>
<listener-class>org.keycloak.example.BootstrapListener</listener-class> <listener-class>org.keycloak.example.BootstrapListener</listener-class>
@ -13,28 +13,8 @@
<security-constraint> <security-constraint>
<web-resource-collection> <web-resource-collection>
<web-resource-name>Customers</web-resource-name> <web-resource-name>UPS</web-resource-name>
<url-pattern>/customers/*</url-pattern> <url-pattern>/ups/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>user</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>AdminConsole</web-resource-name>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>Database</web-resource-name>
<url-pattern>/rest/*</url-pattern>
</web-resource-collection> </web-resource-collection>
<auth-constraint> <auth-constraint>
<role-name>user</role-name> <role-name>user</role-name>
@ -46,7 +26,22 @@
--> -->
</security-constraint> </security-constraint>
<login-config> <security-constraint>
<web-resource-collection>
<web-resource-name>AdminConsole</web-resource-name>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
<!--
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
-->
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method> <auth-method>BASIC</auth-method>
<realm-name>demo</realm-name> <realm-name>demo</realm-name>
</login-config> </login-config>

View file

@ -5,9 +5,9 @@
<title></title> <title></title>
</head> </head>
<body bgcolor="#E3F6CE"> <body bgcolor="#E3F6CE">
<h1>Customer Portal</h1> <h1>Aerogear UPS Portal</h1>
<p><a href="customers/view.jsp">Customer Listing</a></p> <p><a href="ups/view.jsp">Play with Aerogear UPS</a></p>
</body> </body>
</html> </html>

View file

@ -2,7 +2,7 @@
pageEncoding="ISO-8859-1" %> pageEncoding="ISO-8859-1" %>
<html> <html>
<head> <head>
<title>Customer View Page</title> <title>Aerogear - UPS View Page</title>
</head> </head>
<body bgcolor="#E3F6CE"> <body bgcolor="#E3F6CE">

View file

@ -0,0 +1,62 @@
package org.aerogear.ups.security;
import org.keycloak.freemarker.Theme;
import org.keycloak.freemarker.ThemeProvider;
import org.keycloak.theme.ClassLoaderTheme;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class AerogearThemeProvider implements ThemeProvider {
public static final String AEROGEAR = "aerogear";
private static Set<String> ACCOUNT_THEMES = new HashSet<String>();
private static Set<String> LOGIN_THEMES = new HashSet<String>();
private static Set<String> ADMIN_THEMES = new HashSet<String>();
static {
Collections.addAll(ACCOUNT_THEMES, AEROGEAR);
Collections.addAll(LOGIN_THEMES, AEROGEAR);
Collections.addAll(ADMIN_THEMES, AEROGEAR);
}
@Override
public int getProviderPriority() {
return 0;
}
@Override
public Theme createTheme(String name, Theme.Type type) throws IOException {
if (hasTheme(name, type)) {
return new ClassLoaderTheme(name, type, getClass().getClassLoader());
} else {
return null;
}
}
@Override
public Set<String> nameSet(Theme.Type type) {
switch (type) {
case LOGIN:
return LOGIN_THEMES;
case ACCOUNT:
return ACCOUNT_THEMES;
case ADMIN:
return ADMIN_THEMES;
default:
return Collections.emptySet();
}
}
@Override
public boolean hasTheme(String name, Theme.Type type) {
return nameSet(type).contains(name);
}
}

View file

@ -0,0 +1 @@
org.aerogear.ups.security.AerogearThemeProvider

View file

@ -0,0 +1,8 @@
.navbar-title {
background-image: url('../img/logo.png');
height: 65px;
background-repeat: no-repeat;
width: 203px;
margin: 3px 10px 5px;
text-indent: -99999px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View file

@ -0,0 +1,4 @@
parent=keycloak
import=common/keycloak
styles= ../patternfly/lib/patternfly/css/patternfly.css ../patternfly/css/account.css ../keycloak/css/account.css css/account.css

View file

@ -0,0 +1,45 @@
@import url("../lib/patternfly/css/patternfly.css");
@import url("../lib/select2-3.4.1/select2.css");
@import url("admin-console.css");
@import url("tables.css");
@import url("sprites.css");
.navbar-pf {
background-image: url('../img/header-bkgrnd.png');
border-top: 3px solid rgba(255, 255, 255, 0.15);
}
.navbar-pf .navbar-primary {
font-size: 13px;
background-image: -webkit-linear-gradient(top, rgba(0,0,0,0.1) 0%, rgba(0,0,0,.4) 100%);
background-image: linear-gradient(to bottom, rgba(0,0,0,.1) 0%, rgba(0,0,0,.4) 100%);
}
.navbar-pf .navbar-header {
border-bottom: 1px solid rgba(255,255,255,.15);
}
.navbar-pf .navbar-primary li.dropdown.context > a,
.navbar-pf .navbar-primary li.dropdown.context > a:hover,
.navbar-pf .navbar-primary li.dropdown.context.open > a,
.navbar-pf .navbar-primary > .active > a,
.navbar-pf .navbar-primary > .active > a:hover{
background-color: rgba(0,0,0,0.1);
background-image: -webkit-linear-gradient(top, rgba(0,0,0,0.1) 0%, rgba(0,0,0,0.1) 100%);
background-image: linear-gradient(to bottom, rgba(0,0,0,0.1) 0%, rgba(0,0,0,0.1) 100%);
border-bottom: none;
border-right-color: rgba(255,255,255,0.15);
border-top-color: rgba(255,255,255,0.05);
}
/* this is what I added */
.navbar-title {
background-image: url('../img/logo.png');
height: 65px;
background-repeat: no-repeat;
width: 203px;
margin: 3px 10px 5px;
text-indent: -99999px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View file

@ -0,0 +1,4 @@
parent=keycloak
import=common/keycloak
styles= ../keycloak/css/styles.css css/styles.css

View file

@ -0,0 +1,9 @@
#kc-logo-wrapper {
background-image: url("../img/logo.png");
background-repeat: no-repeat;
background-position: top right;
height: 65px;
margin: 100px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View file

@ -0,0 +1,4 @@
parent=keycloak
import=common/keycloak
styles= ../patternfly/lib/patternfly/css/patternfly.css ../patternfly/css/login.css ../patternfly/lib/zocial/zocial.css ../keycloak/css/login.css css/login.css

View file

@ -1,5 +1,5 @@
{ {
"realm": "demo", "realm": "aerogear",
"enabled": true, "enabled": true,
"accessTokenLifespan": 3000, "accessTokenLifespan": 3000,
"accessCodeLifespan": 10, "accessCodeLifespan": 10,
@ -7,6 +7,9 @@
"sslNotRequired": true, "sslNotRequired": true,
"registrationAllowed": false, "registrationAllowed": false,
"social": false, "social": false,
"adminTheme": "aerogear",
"accountTheme": "aerogear",
"loginTheme": "aerogear",
"updateProfileOnInitialSocialLogin": false, "updateProfileOnInitialSocialLogin": false,
"requiredCredentials": [ "password" ], "requiredCredentials": [ "password" ],
"users" : [ "users" : [
@ -24,7 +27,7 @@
{ {
"username" : "admin", "username" : "admin",
"enabled": true, "enabled": true,
"firstName": "Bill", "firstName": "Meister",
"lastName": "Burke", "lastName": "Burke",
"credentials" : [ "credentials" : [
{ "type" : "password", { "type" : "password",
@ -59,19 +62,19 @@
], ],
"scopeMappings": [ "scopeMappings": [
{ {
"client": "customer-portal", "client": "unified-push-server",
"roles": ["user"] "roles": ["user", "admin"]
} }
], ],
"applications": [ "applications": [
{ {
"name": "customer-portal", "name": "unified-push-server",
"enabled": true, "enabled": true,
"publicClient": true, "publicClient": true,
"adminUrl": "/app", "adminUrl": "/aerogear-ups",
"baseUrl": "/app", "baseUrl": "/aerogear-ups",
"redirectUris": [ "redirectUris": [
"/app/*" "/aerogear-ups/*"
] ]
} }
], ],
@ -80,9 +83,13 @@
{ {
"username": "bburke@redhat.com", "username": "bburke@redhat.com",
"roles": ["manage-account"] "roles": ["manage-account"]
},
{
"username": "admin",
"roles": ["manage-account"]
} }
], ],
"demo-realm": [ "realm-management": [
{ {
"username": "admin", "username": "admin",
"roles": ["realm-admin"] "roles": ["realm-admin"]

View file

@ -121,10 +121,16 @@ public class RealmManager {
realm.addScopeMapping(adminConsole, adminRole); realm.addScopeMapping(adminConsole, adminRole);
} }
public String getRealmAdminApplicationName(RealmModel realm) { public String getMasterRealmAdminApplicationName(RealmModel realm) {
return realm.getName() + "-realm"; return realm.getName() + "-realm";
} }
public String getRealmAdminApplicationName(RealmModel realm) {
return "realm-management";
}
protected void setupRealmDefaults(RealmModel realm) { protected void setupRealmDefaults(RealmModel realm) {
// brute force // brute force
realm.setBruteForceProtected(false); // default settings off for now todo set it on realm.setBruteForceProtected(false); // default settings off for now todo set it on
@ -242,7 +248,7 @@ public class RealmManager {
ApplicationManager applicationManager = new ApplicationManager(new RealmManager(identitySession)); ApplicationManager applicationManager = new ApplicationManager(new RealmManager(identitySession));
ApplicationModel realmAdminApp = applicationManager.createApplication(adminRealm, getRealmAdminApplicationName(realm)); ApplicationModel realmAdminApp = applicationManager.createApplication(adminRealm, getMasterRealmAdminApplicationName(realm));
realmAdminApp.setBearerOnly(true); realmAdminApp.setBearerOnly(true);
realm.setMasterAdminApp(realmAdminApp); realm.setMasterAdminApp(realmAdminApp);