KEYCLOAK-60 Replace JSF with FreeMarker template engine
This commit is contained in:
parent
32fcd46e08
commit
b5a4d010ba
55 changed files with 822 additions and 553 deletions
|
@ -56,6 +56,10 @@
|
|||
<groupId>com.google.zxing</groupId>
|
||||
<artifactId>javase</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.freemarker</groupId>
|
||||
<artifactId>freemarker</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -21,33 +21,19 @@
|
|||
*/
|
||||
package org.keycloak.forms;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.faces.bean.ManagedBean;
|
||||
import javax.faces.bean.RequestScoped;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.keycloak.services.resources.flows.FormFlows;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
@ManagedBean(name = "error")
|
||||
@RequestScoped
|
||||
public class ErrorBean {
|
||||
|
||||
private String summary;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
FacesContext ctx = FacesContext.getCurrentInstance();
|
||||
HttpServletRequest request = (HttpServletRequest) ctx.getExternalContext().getRequest();
|
||||
|
||||
summary = (String) request.getAttribute(FormFlows.ERROR_MESSAGE);
|
||||
public ErrorBean(String summary) {
|
||||
this.summary = summary;
|
||||
}
|
||||
|
||||
public String getSummary() {
|
||||
return summary;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -24,25 +24,15 @@ package org.keycloak.forms;
|
|||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.faces.bean.ManagedBean;
|
||||
import javax.faces.bean.ManagedProperty;
|
||||
import javax.faces.bean.RequestScoped;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
|
||||
import org.keycloak.forms.model.RequiredCredential;
|
||||
import org.keycloak.services.resources.flows.FormFlows;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
@ManagedBean(name = "login")
|
||||
@RequestScoped
|
||||
public class LoginBean {
|
||||
|
||||
@ManagedProperty(value = "#{realm}")
|
||||
private RealmBean realm;
|
||||
|
||||
private String username;
|
||||
|
@ -51,13 +41,10 @@ public class LoginBean {
|
|||
|
||||
private List<RequiredCredential> requiredCredentials;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
FacesContext ctx = FacesContext.getCurrentInstance();
|
||||
HttpServletRequest request = (HttpServletRequest) ctx.getExternalContext().getRequest();
|
||||
public LoginBean(RealmBean realm, MultivaluedMap<String, String> formData){
|
||||
|
||||
this.realm = realm;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
MultivaluedMap<String, String> formData = (MultivaluedMap<String, String>) request.getAttribute(FormFlows.DATA);
|
||||
if (formData != null) {
|
||||
username = formData.getFirst("username");
|
||||
password = formData.getFirst("password");
|
||||
|
@ -69,6 +56,7 @@ public class LoginBean {
|
|||
requiredCredentials.add(new RequiredCredential(c.getType(), c.isSecret(), c.getFormLabel()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
|
|
|
@ -21,34 +21,21 @@
|
|||
*/
|
||||
package org.keycloak.forms;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.faces.bean.ManagedBean;
|
||||
import javax.faces.bean.RequestScoped;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.keycloak.services.models.RealmModel;
|
||||
import org.keycloak.services.resources.flows.FormFlows;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
@ManagedBean(name = "realm")
|
||||
@RequestScoped
|
||||
public class RealmBean {
|
||||
|
||||
private RealmModel realm;
|
||||
|
||||
private boolean saas;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
FacesContext ctx = FacesContext.getCurrentInstance();
|
||||
HttpServletRequest request = (HttpServletRequest) ctx.getExternalContext().getRequest();
|
||||
|
||||
realm = (RealmModel) request.getAttribute(FormFlows.REALM);
|
||||
|
||||
saas = RealmModel.DEFAULT_REALM.equals(realm.getName());
|
||||
public RealmBean(RealmModel realmModel) {
|
||||
realm = realmModel;
|
||||
saas = RealmModel.DEFAULT_REALM.equals(realmModel.getName());
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
|
@ -59,7 +46,7 @@ public class RealmBean {
|
|||
return saas ? "Keycloak" : realm.getName();
|
||||
}
|
||||
|
||||
RealmModel getRealm() {
|
||||
public RealmModel getRealm() {
|
||||
return realm;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,39 +24,23 @@ package org.keycloak.forms;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.faces.bean.ManagedBean;
|
||||
import javax.faces.bean.ManagedProperty;
|
||||
import javax.faces.bean.RequestScoped;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
|
||||
import org.keycloak.services.resources.flows.FormFlows;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
@ManagedBean(name = "register")
|
||||
@RequestScoped
|
||||
public class RegisterBean {
|
||||
|
||||
private HashMap<String, String> formData;
|
||||
private Map<String, String> formData = new HashMap<String, String>();
|
||||
|
||||
private boolean socialRegistration;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
FacesContext ctx = FacesContext.getCurrentInstance();
|
||||
HttpServletRequest request = (HttpServletRequest) ctx.getExternalContext().getRequest();
|
||||
public RegisterBean(MultivaluedMap<String, String> formData, boolean socialRegistration) {
|
||||
|
||||
this.formData = new HashMap<String, String>();
|
||||
|
||||
Boolean socialRegistrationAttr = (Boolean)request.getAttribute(FormFlows.SOCIAL_REGISTRATION);
|
||||
this.socialRegistration = socialRegistrationAttr != null && socialRegistrationAttr;
|
||||
this.socialRegistration = socialRegistration;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
MultivaluedMap<String, String> formData = (MultivaluedMap<String, String>) request.getAttribute(FormFlows.DATA);
|
||||
if (formData != null) {
|
||||
for (String k : formData.keySet()) {
|
||||
this.formData.put(k, formData.getFirst(k));
|
||||
|
|
|
@ -26,10 +26,6 @@ import java.util.Iterator;
|
|||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.faces.bean.ManagedBean;
|
||||
import javax.faces.bean.ManagedProperty;
|
||||
import javax.faces.bean.RequestScoped;
|
||||
import javax.imageio.spi.ServiceRegistry;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
|
||||
|
@ -39,28 +35,24 @@ import org.keycloak.services.resources.flows.Urls;
|
|||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
@ManagedBean(name = "social")
|
||||
@RequestScoped
|
||||
public class SocialBean {
|
||||
|
||||
@ManagedProperty(value = "#{realm}")
|
||||
private RealmBean realm;
|
||||
|
||||
@ManagedProperty(value = "#{register}")
|
||||
private RegisterBean registerBean;
|
||||
|
||||
@ManagedProperty(value = "#{url}")
|
||||
private UrlBean url;
|
||||
|
||||
private List<SocialProvider> providers;
|
||||
|
||||
private UriBuilder socialLoginUrlBuilder;
|
||||
public SocialBean(RealmBean realm, RegisterBean registerBean, UrlBean url) {
|
||||
this.realm = realm;
|
||||
this.registerBean = registerBean;
|
||||
this.url = url;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
URI baseURI = url.getBaseURI();
|
||||
|
||||
socialLoginUrlBuilder = UriBuilder.fromUri(Urls.socialRedirectToProviderAuth(baseURI, realm.getId()));
|
||||
UriBuilder socialLoginUrlBuilder = UriBuilder.fromUri(Urls.socialRedirectToProviderAuth(baseURI, realm.getId()));
|
||||
|
||||
providers = new LinkedList<SocialProvider>();
|
||||
for (Iterator<org.keycloak.social.SocialProvider> itr = ServiceRegistry
|
||||
|
|
|
@ -24,23 +24,14 @@ package org.keycloak.forms;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.faces.bean.ManagedBean;
|
||||
import javax.faces.bean.ManagedProperty;
|
||||
import javax.faces.bean.RequestScoped;
|
||||
import javax.faces.context.FacesContext;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
@ManagedBean(name = "template")
|
||||
@RequestScoped
|
||||
public class TemplateBean {
|
||||
|
||||
@ManagedProperty(value = "#{realm}")
|
||||
private RealmBean realm;
|
||||
|
||||
private String theme;
|
||||
private String theme = "default";
|
||||
|
||||
private String themeUrl;
|
||||
|
||||
|
@ -48,9 +39,9 @@ public class TemplateBean {
|
|||
|
||||
private String formsPath;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
formsPath = FacesContext.getCurrentInstance().getExternalContext().getRequestContextPath() + "/forms";
|
||||
|
||||
public TemplateBean(RealmBean realm, String contextPath) {
|
||||
formsPath = contextPath + "/forms";
|
||||
|
||||
// TODO Get theme name from realm
|
||||
theme = "default";
|
||||
|
@ -60,6 +51,7 @@ public class TemplateBean {
|
|||
|
||||
themeConfig.put("styles", themeUrl + "/styles.css");
|
||||
|
||||
// TODO move this into CSS
|
||||
if (realm.isSaas()) {
|
||||
themeConfig.put("logo", themeUrl + "/img/red-hat-logo.png");
|
||||
themeConfig.put("background", themeUrl + "/img/login-screen-background.jpg");
|
||||
|
|
|
@ -25,39 +25,28 @@ import java.io.UnsupportedEncodingException;
|
|||
import java.net.URLEncoder;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.faces.application.FacesMessage;
|
||||
import javax.faces.bean.ManagedBean;
|
||||
import javax.faces.bean.ManagedProperty;
|
||||
import javax.faces.bean.RequestScoped;
|
||||
import javax.faces.context.FacesContext;
|
||||
|
||||
import org.picketlink.common.util.Base32;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
@ManagedBean(name = "totp")
|
||||
@RequestScoped
|
||||
public class TotpBean {
|
||||
|
||||
@ManagedProperty(value = "#{user}")
|
||||
private UserBean user;
|
||||
|
||||
private String totpSecret;
|
||||
private String totpSecretEncoded;
|
||||
private String contextUrl;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
FacesContext facesContext = FacesContext.getCurrentInstance();
|
||||
FacesMessage facesMessage = new FacesMessage("This is a message");
|
||||
facesContext.addMessage(null, facesMessage);
|
||||
public TotpBean(UserBean user, String contextUrl) {
|
||||
this.user = user;
|
||||
this.contextUrl = contextUrl;
|
||||
|
||||
totpSecret = randomString(20);
|
||||
totpSecretEncoded = Base32.encode(totpSecret.getBytes());
|
||||
}
|
||||
|
||||
private static final String randomString(int length) {
|
||||
private static String randomString(int length) {
|
||||
String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVW1234567890";
|
||||
Random r = new Random();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
@ -89,8 +78,7 @@ public class TotpBean {
|
|||
|
||||
public String getTotpSecretQrCodeUrl() throws UnsupportedEncodingException {
|
||||
String contents = URLEncoder.encode("otpauth://totp/keycloak?secret=" + totpSecretEncoded, "utf-8");
|
||||
String contextPath = FacesContext.getCurrentInstance().getExternalContext().getRequestContextPath();
|
||||
return contextPath + "/forms/qrcode" + "?size=200x200&contents=" + contents;
|
||||
return contextUrl + "/forms/qrcode" + "?size=200x200&contents=" + contents;
|
||||
}
|
||||
|
||||
public UserBean getUser() {
|
||||
|
|
|
@ -23,46 +23,20 @@ package org.keycloak.forms;
|
|||
|
||||
import java.net.URI;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.faces.bean.ManagedBean;
|
||||
import javax.faces.bean.ManagedProperty;
|
||||
import javax.faces.bean.RequestScoped;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
|
||||
import org.keycloak.services.resources.flows.FormFlows;
|
||||
import org.keycloak.services.resources.flows.Urls;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
@ManagedBean(name = "url")
|
||||
@RequestScoped
|
||||
public class UrlBean {
|
||||
|
||||
private URI baseURI;
|
||||
|
||||
@ManagedProperty(value = "#{realm}")
|
||||
private RealmBean realm;
|
||||
|
||||
@ManagedProperty(value = "#{register}")
|
||||
private RegisterBean registerBean;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
FacesContext ctx = FacesContext.getCurrentInstance();
|
||||
|
||||
HttpServletRequest request = (HttpServletRequest) ctx.getExternalContext().getRequest();
|
||||
|
||||
UriBuilder b = UriBuilder.fromUri(request.getRequestURI()).replaceQuery(request.getQueryString())
|
||||
.replacePath(request.getContextPath()).path("rest");
|
||||
|
||||
if (request.getAttribute(FormFlows.CODE) != null) {
|
||||
b.queryParam("code", request.getAttribute(FormFlows.CODE));
|
||||
}
|
||||
|
||||
baseURI = b.build();
|
||||
public UrlBean(RealmBean realm, URI baseURI){
|
||||
this.realm = realm;
|
||||
this.baseURI = baseURI;
|
||||
}
|
||||
|
||||
public RealmBean getRealm() {
|
||||
|
@ -73,14 +47,6 @@ public class UrlBean {
|
|||
this.realm = realm;
|
||||
}
|
||||
|
||||
public RegisterBean getRegisterBean() {
|
||||
return registerBean;
|
||||
}
|
||||
|
||||
public void setRegisterBean(RegisterBean registerBean) {
|
||||
this.registerBean = registerBean;
|
||||
}
|
||||
|
||||
public String getAccessUrl() {
|
||||
return Urls.accountAccessPage(baseURI, realm.getId()).toString();
|
||||
}
|
||||
|
@ -115,10 +81,7 @@ public class UrlBean {
|
|||
|
||||
public String getRegistrationAction() {
|
||||
if (realm.isSaas()) {
|
||||
// TODO: saas social registration
|
||||
return Urls.saasRegisterAction(baseURI).toString();
|
||||
} else if (registerBean.isSocialRegistration()) {
|
||||
return Urls.socialRegisterAction(baseURI, realm.getId()).toString();
|
||||
} else {
|
||||
return Urls.realmRegisterAction(baseURI, realm.getId()).toString();
|
||||
}
|
||||
|
@ -126,6 +89,7 @@ public class UrlBean {
|
|||
|
||||
public String getRegistrationUrl() {
|
||||
if (realm.isSaas()) {
|
||||
// TODO: saas social registration
|
||||
return Urls.saasRegisterPage(baseURI).toString();
|
||||
} else {
|
||||
return Urls.realmRegisterPage(baseURI, realm.getId()).toString();
|
||||
|
|
|
@ -21,30 +21,17 @@
|
|||
*/
|
||||
package org.keycloak.forms;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.faces.bean.ManagedBean;
|
||||
import javax.faces.bean.RequestScoped;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.keycloak.services.models.UserModel;
|
||||
import org.keycloak.services.resources.flows.FormFlows;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
@ManagedBean(name = "user")
|
||||
@RequestScoped
|
||||
public class UserBean {
|
||||
|
||||
private UserModel user;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
FacesContext ctx = FacesContext.getCurrentInstance();
|
||||
HttpServletRequest request = (HttpServletRequest) ctx.getExternalContext().getRequest();
|
||||
|
||||
user = (UserModel) request.getAttribute(FormFlows.USER);
|
||||
public UserBean(UserModel user){
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
|
|
250
forms/src/main/java/org/keycloak/service/FormServiceImpl.java
Normal file
250
forms/src/main/java/org/keycloak/service/FormServiceImpl.java
Normal file
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* 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.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.Template;
|
||||
import freemarker.template.TemplateException;
|
||||
import org.jboss.resteasy.logging.Logger;
|
||||
import org.keycloak.forms.ErrorBean;
|
||||
import org.keycloak.forms.LoginBean;
|
||||
import org.keycloak.forms.RealmBean;
|
||||
import org.keycloak.forms.RegisterBean;
|
||||
import org.keycloak.forms.SocialBean;
|
||||
import org.keycloak.forms.TemplateBean;
|
||||
import org.keycloak.forms.TotpBean;
|
||||
import org.keycloak.forms.UrlBean;
|
||||
import org.keycloak.forms.UserBean;
|
||||
import org.keycloak.services.FormService;
|
||||
import org.keycloak.services.resources.flows.Pages;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:vrockai@redhat.com">Viliam Rockai</a>
|
||||
*/
|
||||
public class FormServiceImpl implements FormService {
|
||||
|
||||
private static final Logger log = Logger.getLogger(FormServiceImpl.class);
|
||||
|
||||
private static final String ID = "FormServiceId";
|
||||
private static final String BUNDLE = "org.keycloak.forms.messages";
|
||||
private final Map<String, Command> commandMap = new HashMap<String,Command>();
|
||||
|
||||
public FormServiceImpl(){
|
||||
commandMap.put(Pages.LOGIN, new CommandLogin());
|
||||
commandMap.put(Pages.REGISTER, new CommandRegister());
|
||||
commandMap.put(Pages.ACCOUNT, new CommandAccount());
|
||||
commandMap.put(Pages.PASSWORD, new CommandPassword());
|
||||
commandMap.put(Pages.ACCESS, new CommandAccess());
|
||||
commandMap.put(Pages.LOGIN_TOTP, new CommandLoginTotp());
|
||||
commandMap.put(Pages.SECURITY_FAILURE, new CommandSecurityFailure());
|
||||
commandMap.put(Pages.SOCIAL, new CommandSocial());
|
||||
commandMap.put(Pages.TOTP, new CommandTotp());
|
||||
commandMap.put(Pages.VERIFY_EMAIL, new CommandEmail());
|
||||
}
|
||||
|
||||
public String getId(){
|
||||
return ID;
|
||||
}
|
||||
|
||||
public String process(String pageId, FormServiceDataBean dataBean){
|
||||
|
||||
Map<String, Object> attributes = new HashMap<String, Object>();
|
||||
|
||||
RealmBean realm = new RealmBean(dataBean.getRealm());
|
||||
attributes.put("template", new TemplateBean(realm, dataBean.getContextPath()));
|
||||
|
||||
ResourceBundle rb = ResourceBundle.getBundle(BUNDLE);
|
||||
attributes.put("rb", rb);
|
||||
|
||||
if (commandMap.containsKey(pageId)){
|
||||
commandMap.get(pageId).exec(attributes, dataBean);
|
||||
}
|
||||
|
||||
return processFmTemplate(pageId, attributes);
|
||||
}
|
||||
|
||||
private String processFmTemplate(String temp, Map<String, Object> input) {
|
||||
|
||||
Writer out = new StringWriter();
|
||||
Configuration cfg = new Configuration();
|
||||
|
||||
try {
|
||||
cfg.setClassForTemplateLoading(FormServiceImpl.class,"/META-INF/resources");
|
||||
Template template = cfg.getTemplate(temp);
|
||||
|
||||
template.process(input, out);
|
||||
} catch (IOException e) {
|
||||
log.error("Failed to load the template " + temp, e);
|
||||
} catch (TemplateException e) {
|
||||
log.error("Failed to process template " + temp, e);
|
||||
}
|
||||
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private class CommandTotp implements Command {
|
||||
public void exec(Map<String, Object> attributes, FormServiceDataBean dataBean) {
|
||||
RealmBean realm = new RealmBean(dataBean.getRealm());
|
||||
|
||||
attributes.put("realm", realm);
|
||||
attributes.put("url", new UrlBean(realm, dataBean.getBaseURI()));
|
||||
|
||||
UserBean user = new UserBean(dataBean.getUserModel());
|
||||
attributes.put("user", user);
|
||||
|
||||
TotpBean totp = new TotpBean(user, dataBean.getContextPath());
|
||||
attributes.put("totp", totp);
|
||||
|
||||
attributes.put("login", new LoginBean(realm, dataBean.getFormData()));
|
||||
}
|
||||
}
|
||||
|
||||
private class CommandSocial implements Command {
|
||||
public void exec(Map<String, Object> attributes, FormServiceDataBean dataBean) {
|
||||
RealmBean realm = new RealmBean(dataBean.getRealm());
|
||||
|
||||
attributes.put("url", new UrlBean(realm, dataBean.getBaseURI()));
|
||||
}
|
||||
}
|
||||
|
||||
private class CommandEmail implements Command {
|
||||
public void exec(Map<String, Object> attributes, FormServiceDataBean dataBean) {
|
||||
}
|
||||
}
|
||||
|
||||
private class CommandSecurityFailure implements Command {
|
||||
public void exec(Map<String, Object> attributes, FormServiceDataBean dataBean) {
|
||||
}
|
||||
}
|
||||
|
||||
private class CommandPassword implements Command {
|
||||
public void exec(Map<String, Object> attributes, FormServiceDataBean dataBean) {
|
||||
RealmBean realm = new RealmBean(dataBean.getRealm());
|
||||
|
||||
attributes.put("realm", realm);
|
||||
attributes.put("url", new UrlBean(realm, dataBean.getBaseURI()));
|
||||
attributes.put("user", new UserBean(dataBean.getUserModel()));
|
||||
attributes.put("login", new LoginBean(realm, dataBean.getFormData()));
|
||||
}
|
||||
}
|
||||
|
||||
private class CommandLoginTotp implements Command {
|
||||
public void exec(Map<String, Object> attributes, FormServiceDataBean dataBean) {
|
||||
if (dataBean.getError() != null){
|
||||
attributes.put("error", new ErrorBean(dataBean.getError()));
|
||||
}
|
||||
|
||||
RealmBean realm = new RealmBean(dataBean.getRealm());
|
||||
|
||||
attributes.put("realm", realm);
|
||||
|
||||
UrlBean url = new UrlBean(realm, dataBean.getBaseURI());
|
||||
|
||||
attributes.put("url", url);
|
||||
attributes.put("user", new UserBean(dataBean.getUserModel()));
|
||||
attributes.put("login", new LoginBean(realm, dataBean.getFormData()));
|
||||
|
||||
RegisterBean register = new RegisterBean(dataBean.getFormData(), dataBean.getSocialRegistration());
|
||||
|
||||
SocialBean social = new SocialBean(realm, register, url);
|
||||
attributes.put("social", social);
|
||||
}
|
||||
}
|
||||
|
||||
private class CommandAccess implements Command {
|
||||
public void exec(Map<String, Object> attributes, FormServiceDataBean dataBean) {
|
||||
RealmBean realm = new RealmBean(dataBean.getRealm());
|
||||
|
||||
attributes.put("realm", realm);
|
||||
attributes.put("url", new UrlBean(realm, dataBean.getBaseURI()));
|
||||
}
|
||||
}
|
||||
|
||||
private class CommandAccount implements Command {
|
||||
public void exec(Map<String, Object> attributes, FormServiceDataBean dataBean) {
|
||||
RealmBean realm = new RealmBean(dataBean.getRealm());
|
||||
|
||||
attributes.put("realm", realm);
|
||||
attributes.put("url", new UrlBean(realm, dataBean.getBaseURI()));
|
||||
attributes.put("user", new UserBean(dataBean.getUserModel()));
|
||||
attributes.put("login", new LoginBean(realm, dataBean.getFormData()));
|
||||
}
|
||||
}
|
||||
|
||||
private class CommandLogin implements Command {
|
||||
public void exec(Map<String, Object> attributes, FormServiceDataBean dataBean) {
|
||||
if (dataBean.getError() != null){
|
||||
attributes.put("error", new ErrorBean(dataBean.getError()));
|
||||
}
|
||||
|
||||
RealmBean realm = new RealmBean(dataBean.getRealm());
|
||||
|
||||
attributes.put("realm", realm);
|
||||
|
||||
UrlBean url = new UrlBean(realm, dataBean.getBaseURI());
|
||||
|
||||
attributes.put("url", url);
|
||||
attributes.put("user", new UserBean(dataBean.getUserModel()));
|
||||
attributes.put("login", new LoginBean(realm, dataBean.getFormData()));
|
||||
|
||||
RegisterBean register = new RegisterBean(dataBean.getFormData(), dataBean.getSocialRegistration());
|
||||
|
||||
SocialBean social = new SocialBean(realm, register, url);
|
||||
attributes.put("social", social);
|
||||
}
|
||||
}
|
||||
|
||||
private class CommandRegister implements Command {
|
||||
public void exec(Map<String, Object> attributes, FormServiceDataBean dataBean) {
|
||||
if (dataBean.getError() != null){
|
||||
attributes.put("error", new ErrorBean(dataBean.getError()));
|
||||
}
|
||||
|
||||
RealmBean realm = new RealmBean(dataBean.getRealm());
|
||||
|
||||
attributes.put("realm", realm);
|
||||
|
||||
UrlBean url = new UrlBean(realm, dataBean.getBaseURI());
|
||||
|
||||
attributes.put("url", url);
|
||||
attributes.put("user", new UserBean(dataBean.getUserModel()));
|
||||
|
||||
RegisterBean register = new RegisterBean(dataBean.getFormData(), dataBean.getSocialRegistration());
|
||||
attributes.put("register", register);
|
||||
|
||||
SocialBean social = new SocialBean(realm, register, url);
|
||||
attributes.put("social", social);
|
||||
}
|
||||
}
|
||||
|
||||
private interface Command {
|
||||
public void exec(Map<String, Object> attributes, FormServiceDataBean dataBean);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<faces-config version="2.0" xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd ">
|
||||
|
||||
<application>
|
||||
<resource-bundle>
|
||||
<base-name>org.keycloak.forms.messages</base-name>
|
||||
<var>messages</var>
|
||||
</resource-bundle>
|
||||
</application>
|
||||
|
||||
</faces-config>
|
|
@ -0,0 +1 @@
|
|||
<#include "./theme/" + template.theme + "/access.ftl">
|
|
@ -1,2 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<ui:include xmlns:ui="http://java.sun.com/jsf/facelets" src="theme/#{template.theme}/access.xhtml" />
|
1
forms/src/main/resources/META-INF/resources/forms/account.ftl
Executable file
1
forms/src/main/resources/META-INF/resources/forms/account.ftl
Executable file
|
@ -0,0 +1 @@
|
|||
<#include "./theme/" + template.theme + "/account.ftl">
|
|
@ -1,2 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<ui:include xmlns:ui="http://java.sun.com/jsf/facelets" src="theme/#{template.theme}/account.xhtml" />
|
|
@ -0,0 +1 @@
|
|||
template not found
|
|
@ -0,0 +1 @@
|
|||
<#include "./theme/" + template.theme + "/login-totp.ftl">
|
|
@ -1,2 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<ui:include xmlns:ui="http://java.sun.com/jsf/facelets" src="theme/#{template.theme}/login-totp.xhtml" />
|
|
@ -0,0 +1 @@
|
|||
<#include "./theme/" + template.theme + "/login.ftl">
|
|
@ -1,2 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<ui:include xmlns:ui="http://java.sun.com/jsf/facelets" src="theme/#{template.theme}/login.xhtml" />
|
|
@ -0,0 +1 @@
|
|||
<#include "./theme/" + template.theme + "/password.ftl">
|
|
@ -1,2 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<ui:include xmlns:ui="http://java.sun.com/jsf/facelets" src="theme/#{template.theme}/password.xhtml" />
|
|
@ -0,0 +1 @@
|
|||
<#include "./theme/" + template.theme + "/register.ftl">
|
|
@ -1,2 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<ui:include xmlns:ui="http://java.sun.com/jsf/facelets" src="theme/#{template.theme}/register.xhtml" />
|
|
@ -0,0 +1 @@
|
|||
<#include "./theme/" + template.theme + "/social.ftl">
|
|
@ -1,2 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<ui:include xmlns:ui="http://java.sun.com/jsf/facelets" src="theme/#{template.theme}/social.xhtml" />
|
11
forms/src/main/resources/META-INF/resources/forms/theme/default/access.ftl
Executable file
11
forms/src/main/resources/META-INF/resources/forms/theme/default/access.ftl
Executable file
|
@ -0,0 +1,11 @@
|
|||
<#import "template-main.ftl" as layout>
|
||||
<@layout.mainLayout ; section>
|
||||
|
||||
<#if section = "header">
|
||||
|
||||
Authorized Applications
|
||||
|
||||
<#elseif section = "content">
|
||||
|
||||
</#if>
|
||||
</@layout.mainLayout>
|
|
@ -1,10 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<ui:composition xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets"
|
||||
xmlns:c="http://java.sun.com/jstl/core" template="template-main.xhtml">
|
||||
|
||||
<ui:define name="header">Authorized Applications</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
|
||||
</ui:define>
|
||||
</ui:composition>
|
33
forms/src/main/resources/META-INF/resources/forms/theme/default/account.ftl
Executable file
33
forms/src/main/resources/META-INF/resources/forms/theme/default/account.ftl
Executable file
|
@ -0,0 +1,33 @@
|
|||
<#import "template-main.ftl" as layout>
|
||||
<@layout.mainLayout ; section>
|
||||
|
||||
<#if section = "header">
|
||||
|
||||
Edit Account
|
||||
|
||||
<#elseif section = "content">
|
||||
|
||||
<form action="${url.accountUrl}" method="post">
|
||||
<div>
|
||||
<label for="firstName">${rb.getString('firstName')}</label>
|
||||
<input type="text" id="firstName" name="firstName" value="${user.firstName?default('')}" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="lastName">${rb.getString('lastName')}</label>
|
||||
<input type="text" id="lastName" name="lastName" value="${user.lastName?default('')}" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="email">${rb.getString('email')}</label>
|
||||
<input type="text" id="email" name="email" value="${user.email?default('')}" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="username">${rb.getString('username')}</label>
|
||||
<input type="text" id="username" name="username" value="${user.username?default('')}" disabled="true" />
|
||||
</div>
|
||||
|
||||
<input type="button" value="Cancel" />
|
||||
<input type="submit" value="Save" />
|
||||
</form>
|
||||
|
||||
</#if>
|
||||
</@layout.mainLayout>
|
|
@ -1,30 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<ui:composition xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets"
|
||||
xmlns:c="http://java.sun.com/jstl/core" template="template-main.xhtml">
|
||||
|
||||
<ui:define name="header">Edit Account</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<form action="#{url.accountUrl}" method="post">
|
||||
<div>
|
||||
<label for="firstName">#{messages.firstName}</label>
|
||||
<input type="text" id="firstName" name="firstName" value="#{user.firstName}" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="lastName">#{messages.lastName}</label>
|
||||
<input type="text" id="lastName" name="lastName" value="#{user.lastName}" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="email">#{messages.email}</label>
|
||||
<input type="text" id="email" name="email" value="#{user.email}" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="username">#{messages.username}</label>
|
||||
<input type="text" id="username" name="username" value="#{user.username}" disabled="true" />
|
||||
</div>
|
||||
|
||||
<input type="button" value="Cancel" />
|
||||
<input type="submit" value="Save" />
|
||||
</form>
|
||||
</ui:define>
|
||||
</ui:composition>
|
|
@ -0,0 +1,38 @@
|
|||
<#import "template-login.ftl" as layout>
|
||||
<@layout.registrationLayout bodyClass=""; section>
|
||||
|
||||
<#if section = "title">
|
||||
|
||||
Log in to ${realm.name}
|
||||
|
||||
<#elseif section = "header">
|
||||
|
||||
Log in to <strong>${realm.name}</strong>
|
||||
|
||||
<#elseif section = "form">
|
||||
|
||||
<form action="${url.loginAction}" method="post">
|
||||
<input id="username" name="username" value="${login.username?default('')}" type="hidden" />
|
||||
<input id="password" name="password" value="${login.password?default('')}" type="hidden" />
|
||||
|
||||
<div>
|
||||
<label for="totp">${rb.getString('authenticatorCode')}</label>
|
||||
<input id="totp" name="totp" type="text" />
|
||||
</div>
|
||||
|
||||
<div class="aside-btn">
|
||||
<!-- <input type="checkbox" id="remember" /><label for="remember">Remember Username</label> -->
|
||||
<!-- <p>Forgot <a href="#">Username</a> or <a href="#">Password</a>?</p> -->
|
||||
</div>
|
||||
|
||||
<input type="submit" value="Log In" />
|
||||
</form>
|
||||
|
||||
<#elseif section = "info">
|
||||
|
||||
<#if realm.registrationAllowed>
|
||||
<p>${rb.getString('noAccount')} <a href="${url.registrationUrl}">${rb.getString('register')}</a>.</p>
|
||||
</#if>
|
||||
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
|
@ -1,32 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<ui:composition xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets"
|
||||
xmlns:c="http://java.sun.com/jstl/core" template="template-login.xhtml">
|
||||
|
||||
<ui:define name="title">Log in to #{realm.name}</ui:define>
|
||||
<ui:define name="header">Log in to <strong>#{realm.name}</strong></ui:define>
|
||||
|
||||
<ui:define name="form">
|
||||
<form action="#{url.loginAction}" method="post">
|
||||
<input id="username" name="username" value="#{login.username}" type="hidden" />
|
||||
<input id="password" name="password" value="#{login.password}" type="hidden" />
|
||||
|
||||
<div>
|
||||
<label for="totp">#{messages.authenticatorCode}</label>
|
||||
<input id="totp" name="totp" type="text" />
|
||||
</div>
|
||||
|
||||
<div class="aside-btn">
|
||||
<!-- <input type="checkbox" id="remember" /><label for="remember">Remember Username</label> -->
|
||||
<!-- <p>Forgot <a href="#">Username</a> or <a href="#">Password</a>?</p> -->
|
||||
</div>
|
||||
|
||||
<input type="submit" value="Log In" />
|
||||
</form>
|
||||
</ui:define>
|
||||
|
||||
<ui:define name="info">
|
||||
<h:panelGroup rendered="#{realm.registrationAllowed}">
|
||||
<p>#{messages.noAccount} <a href="#{url.registrationUrl}">#{messages.register}</a>.</p>
|
||||
</h:panelGroup>
|
||||
</ui:define>
|
||||
</ui:composition>
|
42
forms/src/main/resources/META-INF/resources/forms/theme/default/login.ftl
Executable file
42
forms/src/main/resources/META-INF/resources/forms/theme/default/login.ftl
Executable file
|
@ -0,0 +1,42 @@
|
|||
<#import "template-login.ftl" as layout>
|
||||
<@layout.registrationLayout bodyClass=""; section>
|
||||
<#if section = "title">
|
||||
|
||||
Log in to ${realm.name}
|
||||
|
||||
<#elseif section = "header">
|
||||
|
||||
Log in to <strong>${(realm.name)?default('')}</strong>
|
||||
|
||||
<#elseif section = "form">
|
||||
|
||||
<div name="form">
|
||||
<form action="${url.loginAction?default('')}" method="post">
|
||||
<div>
|
||||
<label for="username">${rb.getString('username')}</label>
|
||||
<input id="username" name="username" value="${login.username?default('')}" type="text" />
|
||||
</div>
|
||||
|
||||
<#list login.requiredCredentials as c>
|
||||
<div>
|
||||
<label for="${c.name}">${rb.getString(c.label)}</label> <input id="${c.name}" name="${c.name}" type="${c.inputType}" />
|
||||
</div>
|
||||
</#list>
|
||||
|
||||
<div class="aside-btn">
|
||||
</div>
|
||||
|
||||
<input type="submit" value="Log In" />
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<#elseif section = "info" >
|
||||
|
||||
<div name="info">
|
||||
<#if realm.registrationAllowed>
|
||||
<p>${rb.getString('noAccount')} <a href="${url.registrationUrl?default('')}">${rb.getString('register')}</a>.</p>
|
||||
</#if>
|
||||
</div>
|
||||
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
|
@ -1,35 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<ui:composition xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets"
|
||||
xmlns:c="http://java.sun.com/jstl/core" template="template-login.xhtml">
|
||||
|
||||
<ui:define name="title">Log in to #{realm.name}</ui:define>
|
||||
<ui:define name="header">Log in to <strong>#{realm.name}</strong></ui:define>
|
||||
|
||||
<ui:define name="form">
|
||||
<form action="#{url.loginAction}" method="post">
|
||||
<div>
|
||||
<label for="username">#{messages.username}</label>
|
||||
<input id="username" name="username" value="#{login.username}" type="text" />
|
||||
</div>
|
||||
|
||||
<ui:repeat var="c" value="#{login.requiredCredentials}">
|
||||
<div>
|
||||
<label for="#{c.name}">#{messages[c.label]}</label> <input id="#{c.name}" name="#{c.name}" type="#{c.inputType}" />
|
||||
</div>
|
||||
</ui:repeat>
|
||||
|
||||
<div class="aside-btn">
|
||||
<!-- <input type="checkbox" id="remember" /><label for="remember">Remember Username</label> -->
|
||||
<!-- <p>Forgot <a href="#">Username</a> or <a href="#">Password</a>?</p> -->
|
||||
</div>
|
||||
|
||||
<input type="submit" value="Log In" />
|
||||
</form>
|
||||
</ui:define>
|
||||
|
||||
<ui:define name="info">
|
||||
<h:panelGroup rendered="#{realm.registrationAllowed}">
|
||||
<p>#{messages.noAccount} <a href="#{url.registrationUrl}">#{messages.register}</a>.</p>
|
||||
</h:panelGroup>
|
||||
</ui:define>
|
||||
</ui:composition>
|
29
forms/src/main/resources/META-INF/resources/forms/theme/default/password.ftl
Executable file
29
forms/src/main/resources/META-INF/resources/forms/theme/default/password.ftl
Executable file
|
@ -0,0 +1,29 @@
|
|||
<#import "template-main.ftl" as layout>
|
||||
<@layout.mainLayout ; section>
|
||||
|
||||
<#if section = "header">
|
||||
|
||||
Change Password
|
||||
|
||||
<#elseif section = "content">
|
||||
|
||||
<form action="${url.passwordUrl}" method="post">
|
||||
<div>
|
||||
<label for="password">${rb.getString('password')}</label>
|
||||
<input type="password" id="password" name="password" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="password-new">${rb.getString('passwordNew')}</label>
|
||||
<input type="password" id="password-new" name="password-new" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="password-confirm">${rb.getString('passwordConfirm')}</label>
|
||||
<input type="password" id="password-confirm" name="password-confirm" />
|
||||
</div>
|
||||
|
||||
<input type="button" value="Cancel" />
|
||||
<input type="submit" value="Save" />
|
||||
</form>
|
||||
|
||||
</#if>
|
||||
</@layout.mainLayout>
|
|
@ -1,26 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<ui:composition xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets"
|
||||
xmlns:c="http://java.sun.com/jstl/core" template="template-main.xhtml">
|
||||
|
||||
<ui:define name="header">Change Password</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<form action="#{url.passwordUrl}" method="post">
|
||||
<div>
|
||||
<label for="password">#{messages.password}</label>
|
||||
<input type="password" id="password" name="password" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="password-new">#{messages.passwordNew}</label>
|
||||
<input type="password" id="password-new" name="password-new" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="password-confirm">#{messages.passwordConfirm}</label>
|
||||
<input type="password" id="password-confirm" name="password-confirm" />
|
||||
</div>
|
||||
|
||||
<input type="button" value="Cancel" />
|
||||
<input type="submit" value="Save" />
|
||||
</form>
|
||||
</ui:define>
|
||||
</ui:composition>
|
49
forms/src/main/resources/META-INF/resources/forms/theme/default/register.ftl
Executable file
49
forms/src/main/resources/META-INF/resources/forms/theme/default/register.ftl
Executable file
|
@ -0,0 +1,49 @@
|
|||
<#import "template-login.ftl" as layout>
|
||||
<@layout.registrationLayout bodyClass="register" ; section>
|
||||
|
||||
<#if section = "title">
|
||||
|
||||
${rb.getString('registerWith')} ${realm.name}
|
||||
|
||||
<#elseif section = "header">
|
||||
|
||||
${rb.getString('registerWith')} <strong>${realm.name}</strong>
|
||||
|
||||
<#elseif section = "form">
|
||||
|
||||
<form action="${url.registrationAction}" method="post">
|
||||
<p class="subtitle">${rb.getString('allRequired')}</p>
|
||||
<div>
|
||||
<label for="name">${rb.getString('fullName')}</label>
|
||||
<input type="text" id="name" name="name" value="${register.formData.name?default('')}" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="email">${rb.getString('email')}</label>
|
||||
<input type="text" id="email" name="email" value="${register.formData.email?default('')}" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="username">${rb.getString('username')}</label>
|
||||
<input type="text" id="username" name="username" value="${register.formData.username?default('')}" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="password">${rb.getString('password')}</label>
|
||||
<input type="password" id="password" name="password" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="password-confirm">${rb.getString('passwordConfirm')}</label>
|
||||
<input type="password" id="password-confirm" name="password-confirm" />
|
||||
</div>
|
||||
|
||||
<div class="aside-btn">
|
||||
<p>By registering you agree to the <a href="#">Terms of Service</a> and the <a href="#">Privacy Policy</a>.</p>
|
||||
</div>
|
||||
|
||||
<input type="submit" value="Register" />
|
||||
</form>
|
||||
|
||||
<#elseif section = "info">
|
||||
|
||||
<p>${rb.getString('alreadyHaveAccount')} <a href="${url.loginUrl}">${rb.getString('logIn')}</a>.</p>
|
||||
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
|
@ -1,47 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<ui:composition xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets"
|
||||
xmlns:c="http://java.sun.com/jstl/core" template="template-login.xhtml">
|
||||
|
||||
<ui:param name="bodyClass" value="register" />
|
||||
|
||||
<ui:define name="title">#{messages.registerWith} #{realm.name}</ui:define>
|
||||
<ui:define name="header">#{messages.registerWith} <strong>#{realm.name}</strong></ui:define>
|
||||
|
||||
<ui:define name="form">
|
||||
<form action="#{url.registrationAction}" method="post">
|
||||
<p class="subtitle">#{messages.allRequired}</p>
|
||||
<div>
|
||||
<label for="name">#{messages.fullName}</label>
|
||||
<input type="text" id="name" name="name" value="#{register.formData['name']}" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="email">#{messages.email}</label>
|
||||
<input type="text" id="email" name="email" value="#{register.formData['email']}" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="username">#{messages.username}</label>
|
||||
<input type="text" id="username" name="username" value="#{register.formData['username']}" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="password">#{messages.password}</label>
|
||||
<input type="password" id="password" name="password" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="password-confirm">#{messages.passwordConfirm}</label>
|
||||
<input type="password" id="password-confirm" name="password-confirm" />
|
||||
</div>
|
||||
|
||||
<div class="aside-btn">
|
||||
<p>By registering you agree to the <a href="#">Terms of Service</a> and the <a href="#">Privacy Policy</a>.</p>
|
||||
</div>
|
||||
|
||||
<input type="submit" value="Register" />
|
||||
</form>
|
||||
</ui:define>
|
||||
|
||||
<ui:define name="info">
|
||||
<h:panelGroup rendered="#{not register.socialRegistration}">
|
||||
<p>#{messages.alreadyHaveAccount} <a href="#{url.loginUrl}">#{messages.logIn}</a>.</p>
|
||||
</h:panelGroup>
|
||||
</ui:define>
|
||||
</ui:composition>
|
12
forms/src/main/resources/META-INF/resources/forms/theme/default/social.ftl
Executable file
12
forms/src/main/resources/META-INF/resources/forms/theme/default/social.ftl
Executable file
|
@ -0,0 +1,12 @@
|
|||
<#import "template-main.ftl" as layout>
|
||||
<@layout.mainLayout ; section>
|
||||
|
||||
<#if section = "header">
|
||||
|
||||
Social Accounts
|
||||
|
||||
<#elseif section = "content">
|
||||
|
||||
|
||||
</#if>
|
||||
</@layout.mainLayout>
|
|
@ -1,10 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<ui:composition xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets"
|
||||
xmlns:c="http://java.sun.com/jstl/core" template="template-main.xhtml">
|
||||
|
||||
<ui:define name="header">Social Accounts</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
|
||||
</ui:define>
|
||||
</ui:composition>
|
|
@ -0,0 +1,75 @@
|
|||
<#macro registrationLayout bodyClass>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>
|
||||
<#nested "title">
|
||||
</title>
|
||||
<link href="${template.themeConfig.styles}" rel="stylesheet" />
|
||||
<style>
|
||||
body {
|
||||
background-image: url("${template.themeConfig.background}");
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="rcue-login-register ${bodyClass}">
|
||||
<#if (template.themeConfig.logo)?has_content>
|
||||
<h1>
|
||||
<a href="#" title="Go to the home page"><img src="${template.themeConfig.logo}" alt="Logo" /></a>
|
||||
</h1>
|
||||
</#if>
|
||||
|
||||
<div class="content">
|
||||
<h2>
|
||||
<#nested "header">
|
||||
</h2>
|
||||
|
||||
<div class="background-area">
|
||||
<div class="form-area ${(realm.social)?string('social','')} clearfix">
|
||||
<section class="app-form">
|
||||
<h3>Application login area</h3>
|
||||
<#nested "form">
|
||||
</section>
|
||||
|
||||
<#if error?has_content>
|
||||
<div class="feedback error bottom-left show">
|
||||
<p>
|
||||
<strong id="loginError">${rb.getString(error.summary)}</strong>
|
||||
</p>
|
||||
</div>
|
||||
</#if>
|
||||
|
||||
<#if social.displaySocialProviders>
|
||||
<section class="social-login"> <span>or</span>
|
||||
<h3>Social login area</h3>
|
||||
<p>${rb.getString('logInWith')}</p>
|
||||
<ul>
|
||||
<#list social.providers as p>
|
||||
<li><a href="${p.loginUrl}" class="zocial ${p.id}"> <span class="text">${p.name}</span></a></li>
|
||||
</#list>
|
||||
</ul>
|
||||
</section>
|
||||
</#if>
|
||||
|
||||
<section class="info-area">
|
||||
<h3>Info area</h3>
|
||||
<#nested "info">
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<#if template.themeConfig['displayPoweredBy']>
|
||||
<p class="powered">
|
||||
<a href="#">${rb.getString('poweredByKeycloak')}</a>
|
||||
</p>
|
||||
</#if>
|
||||
</div>
|
||||
|
||||
<#nested "content">
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</#macro>
|
|
@ -1,71 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html">
|
||||
|
||||
<h:head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title><ui:insert name="title" /></title>
|
||||
<link href="#{template.themeConfig['styles']}" rel="stylesheet" />
|
||||
<style>
|
||||
body {
|
||||
background-image: url("#{template.themeConfig['background']}");
|
||||
}
|
||||
</style>
|
||||
</h:head>
|
||||
|
||||
<h:body class="rcue-login-register #{bodyClass}">
|
||||
<h:panelGroup rendered="#{not empty template.themeConfig['logo']}">
|
||||
<h1>
|
||||
<a href="#" title="Go to the home page"><img src="#{template.themeConfig['logo']}" alt="Logo" /></a>
|
||||
</h1>
|
||||
</h:panelGroup>
|
||||
|
||||
<div class="content">
|
||||
<h2>
|
||||
<ui:insert name="header" />
|
||||
</h2>
|
||||
|
||||
<div class="background-area">
|
||||
<div class="form-area #{realm.social ? 'social' : ''} clearfix">
|
||||
<section class="app-form">
|
||||
<h3>Application login area</h3>
|
||||
<ui:insert name="form" />
|
||||
</section>
|
||||
|
||||
<h:panelGroup rendered="#{not empty error.summary}">
|
||||
<div class="feedback error bottom-left show">
|
||||
<p>
|
||||
<strong id="loginError">#{messages[error.summary]}</strong>
|
||||
</p>
|
||||
</div>
|
||||
</h:panelGroup>
|
||||
|
||||
<h:panelGroup rendered="#{social.displaySocialProviders}">
|
||||
<section class="social-login"> <span>or</span>
|
||||
<h3>Social login area</h3>
|
||||
<p>#{messages.logInWith}</p>
|
||||
<ul>
|
||||
<ui:repeat var="p" value="#{social.providers}">
|
||||
<li><a href="#{p.loginUrl}" class="zocial #{p.id}"> <span class="text">#{p.name}</span></a></li>
|
||||
</ui:repeat>
|
||||
</ul>
|
||||
</section>
|
||||
</h:panelGroup>
|
||||
|
||||
<section class="info-area">
|
||||
<h3>Info area</h3>
|
||||
<ui:insert name="info" />
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h:panelGroup rendered="#{template.themeConfig['displayPoweredBy']}">
|
||||
<p class="powered">
|
||||
<a href="#">#{messages.poweredByKeycloak}</a>
|
||||
</p>
|
||||
</h:panelGroup>
|
||||
</div>
|
||||
|
||||
<ui:insert name="content" />
|
||||
|
||||
</h:body>
|
||||
</html>
|
|
@ -1,28 +1,29 @@
|
|||
<#macro mainLayout>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html">
|
||||
|
||||
<h:head>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>Keycloak Account Management</title>
|
||||
<link href="#{template.formsPath}/lib/bootstrap/css/bootstrap.css" rel="stylesheet" />
|
||||
<link href="${template.formsPath}/lib/bootstrap/css/bootstrap.css" rel="stylesheet" />
|
||||
<style>
|
||||
body {
|
||||
padding-top: 50px;
|
||||
}
|
||||
</style>
|
||||
</h:head>
|
||||
</head>
|
||||
|
||||
<h:body>
|
||||
<body>
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="container">
|
||||
<div class="collapse navbar-collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="#{url.accountUrl}">Account</a></li>
|
||||
<li><a href="#{url.passwordUrl}">Password</a></li>
|
||||
<li><a href="#{url.totpUrl}">Authenticator</a></li>
|
||||
<li><a href="#{url.socialUrl}">Social Accounts</a></li>
|
||||
<li><a href="#{url.accessUrl}">Authorized Access</a></li>
|
||||
<li><a href="${url.accountUrl}">Account</a></li>
|
||||
<li><a href="${url.passwordUrl}">Password</a></li>
|
||||
<li><a href="${url.totpUrl}">Authenticator</a></li>
|
||||
<li><a href="${url.socialUrl}">Social Accounts</a></li>
|
||||
<li><a href="${url.accessUrl}">Authorized Access</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -30,15 +31,16 @@ body {
|
|||
|
||||
<div class="container">
|
||||
<h1>
|
||||
<ui:insert name="header" />
|
||||
<#nested "header">
|
||||
</h1>
|
||||
|
||||
<h:panelGroup rendered="#{not empty error.summary}">
|
||||
<div class="alert alert-danger">#{messages[error.summary]}</div>
|
||||
</h:panelGroup>
|
||||
|
||||
<ui:insert name="content" />
|
||||
<#if error?has_content>
|
||||
<div class="alert alert-danger">${rb.getString(error.summary)}</div>
|
||||
</#if>
|
||||
|
||||
<#nested "content">
|
||||
</div>
|
||||
|
||||
</h:body>
|
||||
</html>
|
||||
</body>
|
||||
</html>
|
||||
</#macro>
|
38
forms/src/main/resources/META-INF/resources/forms/theme/default/totp.ftl
Executable file
38
forms/src/main/resources/META-INF/resources/forms/theme/default/totp.ftl
Executable file
|
@ -0,0 +1,38 @@
|
|||
<#import "template-main.ftl" as layout>
|
||||
<@layout.mainLayout ; section>
|
||||
|
||||
<#if section = "header">
|
||||
|
||||
Google Authenticator Setup
|
||||
|
||||
<#elseif section = "content">
|
||||
|
||||
<!--h:messages globalOnly="true" /-->
|
||||
<#if totp.enabled>
|
||||
Google Authenticator enabled
|
||||
<#else>
|
||||
<h2>To setup Google Authenticator</h2>
|
||||
|
||||
<ol>
|
||||
<li>Install Google Authenticator to your device</li>
|
||||
<li>Set up an account in Google Authenticator and scan the QR code below or enter the key<br />
|
||||
<img src="${totp.totpSecretQrCodeUrl}" /> ${totp.totpSecretEncoded}
|
||||
</li>
|
||||
<li>Enter a one-time password provided by Google Authenticator and click Save to finish the setup
|
||||
|
||||
<form action="${url.totpUrl}" method="post">
|
||||
<div>
|
||||
<label for="totp">${rb.getString('authenticatorCode')}</label>
|
||||
<input type="text" id="totp" name="totp" />
|
||||
<input type="hidden" id="totpSecret" name="totpSecret" value="${totp.totpSecret}" />
|
||||
</div>
|
||||
|
||||
<input type="button" value="Cancel" />
|
||||
<input type="submit" value="Save" />
|
||||
</form>
|
||||
</li>
|
||||
</ol>
|
||||
</#if>
|
||||
|
||||
</#if>
|
||||
</@layout.mainLayout>
|
|
@ -1,37 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<ui:composition xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets"
|
||||
xmlns:c="http://java.sun.com/jstl/core" template="template-main.xhtml">
|
||||
|
||||
<ui:define name="header">Google Authenticator Setup</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<h:messages globalOnly="true" />
|
||||
<h:panelGroup rendered="#{totp.enabled}">
|
||||
Google Authenticator enabled
|
||||
</h:panelGroup>
|
||||
|
||||
<h:panelGroup rendered="#{not totp.enabled}">
|
||||
<h2>To setup Google Authenticator</h2>
|
||||
|
||||
<ol>
|
||||
<li>Install Google Authenticator to your device</li>
|
||||
<li>Set up an account in Google Authenticator and scan the QR code below or enter the key<br />
|
||||
<img src="#{totp.totpSecretQrCodeUrl}" /> #{totp.totpSecretEncoded}
|
||||
</li>
|
||||
<li>Enter a one-time password provided by Google Authenticator and click Save to finish the setup
|
||||
|
||||
<form action="#{url.totpUrl}" method="post">
|
||||
<div>
|
||||
<label for="totp">#{messages.authenticatorCode}</label>
|
||||
<input type="text" id="totp" name="totp" />
|
||||
<input type="hidden" id="totpSecret" name="totpSecret" value="#{totp.totpSecret}" />
|
||||
</div>
|
||||
|
||||
<input type="button" value="Cancel" />
|
||||
<input type="submit" value="Save" />
|
||||
</form>
|
||||
</li>
|
||||
</ol>
|
||||
</h:panelGroup>
|
||||
</ui:define>
|
||||
</ui:composition>
|
|
@ -0,0 +1 @@
|
|||
<#include "./theme/" + template.theme + "/totp.ftl">
|
|
@ -1,2 +0,0 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<ui:include xmlns:ui="http://java.sun.com/jsf/facelets" src="theme/#{template.theme}/totp.xhtml" />
|
|
@ -0,0 +1 @@
|
|||
org.keycloak.service.FormServiceImpl
|
|
@ -1,16 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-fragment version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd ">
|
||||
|
||||
<servlet>
|
||||
<servlet-name>Faces Servlet</servlet-name>
|
||||
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>Faces Servlet</servlet-name>
|
||||
<url-pattern>*.xhtml</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
</web-fragment>
|
5
pom.xml
5
pom.xml
|
@ -191,6 +191,11 @@
|
|||
<artifactId>google-api-client</artifactId>
|
||||
<version>1.14.1-beta</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.freemarker</groupId>
|
||||
<artifactId>freemarker</artifactId>
|
||||
<version>2.3.19</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Google+ -->
|
||||
<dependency>
|
||||
|
|
125
services/src/main/java/org/keycloak/services/FormService.java
Normal file
125
services/src/main/java/org/keycloak/services/FormService.java
Normal file
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* 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.services;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
|
||||
import org.keycloak.services.models.RealmModel;
|
||||
import org.keycloak.services.models.UserModel;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:vrockai@redhat.com">Viliam Rockai</a>
|
||||
*/
|
||||
public interface FormService {
|
||||
|
||||
String getId();
|
||||
|
||||
public String process(String pageId, FormServiceDataBean data);
|
||||
|
||||
public static class FormServiceDataBean {
|
||||
|
||||
private RealmModel realm;
|
||||
private UserModel userModel;
|
||||
private String error;
|
||||
private MultivaluedMap<String, String> formData;
|
||||
private URI baseURI;
|
||||
|
||||
public Boolean getSocialRegistration() {
|
||||
return socialRegistration;
|
||||
}
|
||||
|
||||
public void setSocialRegistration(Boolean socialRegistration) {
|
||||
this.socialRegistration = socialRegistration;
|
||||
}
|
||||
|
||||
private Boolean socialRegistration;
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
private String code;
|
||||
|
||||
public String getContextPath() {
|
||||
return contextPath;
|
||||
}
|
||||
|
||||
public void setContextPath(String contextPath) {
|
||||
this.contextPath = contextPath;
|
||||
}
|
||||
|
||||
private String contextPath;
|
||||
|
||||
public FormServiceDataBean(RealmModel realm, UserModel userModel, MultivaluedMap<String, String> formData, String error){
|
||||
this.realm = realm;
|
||||
this.userModel = userModel;
|
||||
this.formData = formData;
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public URI getBaseURI() {
|
||||
return baseURI;
|
||||
}
|
||||
|
||||
public void setBaseURI(URI baseURI) {
|
||||
this.baseURI = baseURI;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public void setError(String error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public MultivaluedMap<String, String> getFormData() {
|
||||
return formData;
|
||||
}
|
||||
|
||||
public void setFormData(MultivaluedMap<String, String> formData) {
|
||||
this.formData = formData;
|
||||
}
|
||||
|
||||
public RealmModel getRealm() {
|
||||
return realm;
|
||||
}
|
||||
|
||||
public RealmModel setRealm(RealmModel realm) {
|
||||
return realm;
|
||||
}
|
||||
|
||||
public UserModel getUserModel() {
|
||||
return userModel;
|
||||
}
|
||||
|
||||
public void setUserModel(UserModel userModel) {
|
||||
this.userModel = userModel;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,15 +21,22 @@
|
|||
*/
|
||||
package org.keycloak.services.resources.flows;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.jboss.resteasy.spi.HttpRequest;
|
||||
import org.jboss.resteasy.spi.ResteasyUriInfo;
|
||||
import org.keycloak.services.FormService;
|
||||
import org.keycloak.services.email.EmailSender;
|
||||
import org.keycloak.services.models.RealmModel;
|
||||
import org.keycloak.services.models.UserModel;
|
||||
import org.keycloak.services.models.UserModel.RequiredAction;
|
||||
import org.picketlink.idm.model.sample.Realm;
|
||||
|
||||
import javax.imageio.spi.ServiceRegistry;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
/**
|
||||
|
@ -85,29 +92,43 @@ public class FormFlows {
|
|||
return forwardToForm(Pages.ACCOUNT);
|
||||
}
|
||||
|
||||
private Response forwardToForm(String form) {
|
||||
request.setAttribute(REALM, realm);
|
||||
private Response forwardToForm(String template) {
|
||||
|
||||
if (error != null) {
|
||||
request.setAttribute(ERROR_MESSAGE, error);
|
||||
FormService.FormServiceDataBean formDataBean = new FormService.FormServiceDataBean(realm, userModel, formData, error);
|
||||
|
||||
// Getting URI needed by form processing service
|
||||
ResteasyUriInfo uriInfo = request.getUri();
|
||||
MultivaluedMap<String, String> queryParameterMap = uriInfo.getQueryParameters();
|
||||
|
||||
String requestURI = uriInfo.getBaseUri().getPath();
|
||||
UriBuilder uriBuilder = UriBuilder.fromUri(requestURI);
|
||||
|
||||
for(String k : queryParameterMap.keySet()){
|
||||
uriBuilder.replaceQueryParam(k, queryParameterMap.get(k).toArray());
|
||||
}
|
||||
|
||||
if (formData != null) {
|
||||
request.setAttribute(DATA, formData);
|
||||
if (code != null){
|
||||
uriBuilder.queryParam(CODE, code);
|
||||
}
|
||||
|
||||
if (userModel != null) {
|
||||
request.setAttribute(USER, userModel);
|
||||
URI baseURI = uriBuilder.build();
|
||||
formDataBean.setBaseURI(baseURI);
|
||||
|
||||
// TODO find a better way to obtain contextPath
|
||||
// Getting context path by removing "rest/" substring from the BaseUri path
|
||||
formDataBean.setContextPath(requestURI.substring(0,requestURI.length()-5));
|
||||
formDataBean.setSocialRegistration(socialRegistration);
|
||||
|
||||
// Find the service and process relevant template
|
||||
Iterator<FormService> itr = ServiceRegistry.lookupProviders(FormService.class);
|
||||
|
||||
while (itr.hasNext()) {
|
||||
FormService provider = itr.next();
|
||||
if (provider.getId().equals("FormServiceId"))
|
||||
return Response.status(200).entity(provider.process(template, formDataBean)).build();
|
||||
}
|
||||
|
||||
if (code != null) {
|
||||
request.setAttribute(CODE, code);
|
||||
}
|
||||
|
||||
request.setAttribute(SOCIAL_REGISTRATION, socialRegistration);
|
||||
|
||||
request.forward(form);
|
||||
return null;
|
||||
return Response.status(200).entity("form provider not found").build();
|
||||
}
|
||||
|
||||
public Response forwardToLogin() {
|
||||
|
|
|
@ -26,26 +26,26 @@ package org.keycloak.services.resources.flows;
|
|||
*/
|
||||
public class Pages {
|
||||
|
||||
public final static String ACCESS = "/forms/access.xhtml";
|
||||
public final static String ACCESS = "/forms/access.ftl";
|
||||
|
||||
public final static String ACCOUNT = "/forms/account.xhtml";
|
||||
public final static String ACCOUNT = "/forms/account.ftl";
|
||||
|
||||
public final static String LOGIN = "/forms/login.xhtml";
|
||||
public final static String LOGIN = "/forms/login.ftl";
|
||||
|
||||
public final static String LOGIN_TOTP = "/forms/login-totp.xhtml";
|
||||
public final static String LOGIN_TOTP = "/forms/login-totp.ftl";
|
||||
|
||||
public final static String OAUTH_GRANT = "/saas/oauthGrantForm.jsp";
|
||||
|
||||
public final static String PASSWORD = "/forms/password.xhtml";
|
||||
public final static String PASSWORD = "/forms/password.ftl";
|
||||
|
||||
public final static String REGISTER = "/forms/register.xhtml";
|
||||
public final static String REGISTER = "/forms/register.ftl";
|
||||
|
||||
public final static String SECURITY_FAILURE = "/saas/securityFailure.jsp";
|
||||
|
||||
public final static String SOCIAL = "/forms/social.xhtml";
|
||||
public final static String SOCIAL = "/forms/social.ftl";
|
||||
|
||||
public final static String TOTP = "/forms/totp.xhtml";
|
||||
public final static String TOTP = "/forms/totp.ftl";
|
||||
|
||||
public final static String VERIFY_EMAIL = "/forms/verify-email.xhtml";
|
||||
public final static String VERIFY_EMAIL = "/forms/verify-email.ftl";
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue