Renamed sdk-html for forms and added registration form

This commit is contained in:
Stian Thorgersen 2013-08-14 12:30:16 +01:00
parent 8876484a87
commit 0ffe1cb354
44 changed files with 277 additions and 181 deletions

View file

@ -52,7 +52,7 @@
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-sdk-html</artifactId>
<artifactId>keycloak-forms</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>

View file

@ -12,8 +12,8 @@
<!-- <select class="nav pull-left" ng-options="r.name for r in current.realms"></select> -->
</div>
<ul class="nav pull-right" data-ng-hide="auth.loggedIn">
<li><a href="/auth-server/rest/saas/loginPage.html">Login</a></li>
<li><a href="/auth-server/saas/saas-register.jsp">Register</a></li>
<li><a href="/auth-server/rest/saas/login">Login</a></li>
<li><a href="/auth-server/rest/saas/registrations">Register</a></li>
</ul>
<ul class="nav pull-right" data-ng-show="auth.loggedIn">
<li class="divider-vertical-left dropdown"><a data-toggle="dropdown" class="dropdown-toggle" href="#"><i

View file

@ -1,88 +0,0 @@
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%><!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Register with Keycloak</title>
<link rel="stylesheet" href="<%=application.getContextPath()%>/saas/css/reset.css">
<link rel="stylesheet" type="text/css" href="<%=application.getContextPath()%>/saas/css/base.css">
<link rel="stylesheet" type="text/css" href="<%=application.getContextPath()%>/saas/css/forms.css">
<link rel="stylesheet" type="text/css" href="<%=application.getContextPath()%>/saas/css/zocial/zocial.css">
<link rel="stylesheet" type="text/css" href="<%=application.getContextPath()%>/saas/css/login-screen.css">
<link rel="stylesheet" type="text/css" href='http://fonts.googleapis.com/css?family=Open+Sans:400,300,300italic,400italic,600,600italic,700,700italic,800,800italic'>
</head>
<body class="rcue-login-register register">
<h1><a href="#" title="Go to the home page"><img src="<%=application.getContextPath()%>/saas/img/red-hat-logo.png" alt="Red Hat logo"></a></h1>
<div class="content">
<h2>Register with <strong>Keycloak</strong></h2>
<div class="background-area">
<div class="form-area social clearfix">
<section class="app-form">
<h3>Application login area</h3>
<form action="<%=application.getContextPath()%>/rest/saas/registrations" method="POST">
<%
String errorMessage = (String)request.getAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE");
if (errorMessage != null) { %>
<div class="feedback feedback-error">
<p><font color="red"><%=errorMessage%></font></p>
</div>
<% } %>
<p class="subtitle">All fields required</p>
<div>
<label for="name">Full name</label><input type="text" id="name" name="name" autofocus>
</div>
<div>
<label for="email">Email</label><input type="email" id="email" name="email">
</div>
<div>
<label for="username">Username</label><input type="text" id="username" name="username">
</div>
<div>
<label for="password">Password</label><input type="password" id="password" placeholder="At least 6 characters" name="password">
</div>
<div>
<label for="password-confirm" class="two-lines">Password confirmation</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>
</section>
<section class="social-login">
<span>or</span>
<h3>Social login area</h3>
<p>Log In with</p>
<ul>
<li>
<a href="#" class="zocial facebook">
<span class="text">Facebook</span>
</a>
</li>
<li>
<a href="#" class="zocial googleplus">
<span class="text">Google</span>
</a>
</li>
<li>
<a href="#" class="zocial twitter">
<span class="text">Twitter</span>
</a>
</li>
</ul>
</section>
<section class="info-area">
<h3>Info area</h3>
<p>Already have an account? <a href="<%=application.getContextPath()%>/rest/saas/loginPage.html">Log in</a>.</p>
<ul>
<li><strong>Domain:</strong> 10.0.0.1</li>
<li><strong>Zone:</strong> Live</li>
<li><strong>Appliance:</strong> Yep</li>
</ul>
</section>
</div>
</div>
</div>
</body>
</html>

View file

@ -8,8 +8,8 @@
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>keycloak-sdk-html</artifactId>
<name>Keycloak HTML SDK</name>
<artifactId>keycloak-forms</artifactId>
<name>Keycloak Forms</name>
<description />
<dependencies>

View file

@ -8,31 +8,33 @@ import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.FacesContext;
import javax.imageio.spi.ServiceRegistry;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.MultivaluedMap;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RequiredCredentialModel;
@ManagedBean(name = "login")
@ManagedBean(name = "forms")
@RequestScoped
public class LoginBean {
public class FormsBean {
private RealmModel realm;
private String name;
private String loginUrl;
private String loginAction;
private String socialLoginUrl;
private String registrationUrl;
private String username;
private String registrationAction;
private List<RequiredCredential> requiredCredentials;
@ -48,6 +50,12 @@ public class LoginBean {
private String error;
private String errorDetails;
private String view;
private Map<String, String> formData;
@PostConstruct
public void init() {
FacesContext ctx = FacesContext.getCurrentInstance();
@ -62,13 +70,19 @@ public class LoginBean {
name = realm.getName();
}
view = ctx.getViewRoot().getViewId();
view = view.substring(view.lastIndexOf('/') + 1, view.lastIndexOf('.'));
loginUrl = ((URI) request.getAttribute("KEYCLOAK_LOGIN_PAGE")).toString();
loginAction = ((URI) request.getAttribute("KEYCLOAK_LOGIN_ACTION")).toString();
registrationUrl = ((URI) request.getAttribute("KEYCLOAK_REGISTRATION_PAGE")).toString();
registrationAction = ((URI) request.getAttribute("KEYCLOAK_REGISTRATION_ACTION")).toString();
socialLoginUrl = ((URI) request.getAttribute("KEYCLOAK_SOCIAL_LOGIN")).toString();
username = (String) request.getAttribute("username");
addRequiredCredentials();
addFormData(request);
addHiddenProperties(request, "client_id", "scope", "state", "redirect_uri");
addSocialProviders();
addErrors(request);
@ -98,6 +112,10 @@ public class LoginBean {
return name;
}
public String getLoginUrl() {
return loginUrl;
}
public String getLoginAction() {
return loginAction;
}
@ -106,6 +124,14 @@ public class LoginBean {
return error;
}
public String getErrorDetails() {
return errorDetails;
}
public Map<String, String> getFormData() {
return formData;
}
public List<Property> getHiddenProperties() {
return hiddenProperties;
}
@ -114,6 +140,10 @@ public class LoginBean {
return requiredCredentials;
}
public String getView() {
return view;
}
public String getTheme() {
return theme;
}
@ -126,8 +156,8 @@ public class LoginBean {
return registrationUrl;
}
public String getUsername() {
return username;
public String getRegistrationAction() {
return registrationAction;
}
public boolean isSocial() {
@ -139,6 +169,18 @@ public class LoginBean {
return realm.isRegistrationAllowed();
}
private void addFormData(HttpServletRequest request) {
formData = new HashMap<String, String>();
@SuppressWarnings("unchecked")
MultivaluedMap<String, String> t = (MultivaluedMap<String, String>) request.getAttribute("KEYCLOAK_FORM_DATA");
if (t != null) {
for (String k : t.keySet()) {
formData.put(k, t.getFirst(k));
}
}
}
private void addHiddenProperties(HttpServletRequest request, String... names) {
hiddenProperties = new LinkedList<Property>();
for (String name : names) {
@ -170,6 +212,16 @@ public class LoginBean {
private void addErrors(HttpServletRequest request) {
error = (String) request.getAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE");
if (error != null) {
if (view.equals("login")) {
errorDetails = error;
error = "Login failed";
} else if (view.equals("register")) {
errorDetails = error;
error = "Registration failed";
}
}
}
public class Property {

View file

@ -1,2 +1,2 @@
<!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/#{login.theme}/login.xhtml" />
<ui:include xmlns:ui="http://java.sun.com/jsf/facelets" src="theme/#{forms.theme}/login.xhtml" />

View file

@ -1,2 +1,2 @@
<!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/#{login.theme}/register.xhtml" />
<ui:include xmlns:ui="http://java.sun.com/jsf/facelets" src="theme/#{forms.theme}/register.xhtml" />

View file

@ -2,27 +2,28 @@
<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.xhtml">
<ui:define name="header">Log in to <strong>#{login.name}</strong></ui:define>
<ui:define name="header">Log in to <strong>#{forms.name}</strong></ui:define>
<ui:define name="form">
<form action="#{login.loginAction}" method="post">
<form action="#{forms.loginAction}" method="post">
<div>
<label for="username">Username</label> <input id="username" name="username" value="#{login.username}" type="text" />
<label for="username">Username</label>
<input id="username" name="username" value="#{forms.formData['username']}" type="text" />
</div>
<ui:repeat var="c" value="#{login.requiredCredentials}">
<ui:repeat var="c" value="#{forms.requiredCredentials}">
<div>
<label for="#{c.name}">#{c.label}</label> <input id="#{c.name}" name="#{c.name}" type="#{c.inputType}" />
</div>
</ui:repeat>
<ui:repeat var="p" value="#{login.hiddenProperties}">
<ui:repeat var="p" value="#{forms.hiddenProperties}">
<input name="#{p.name}" value="#{p.value}" type="hidden" />
</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>
<!-- <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" />
@ -30,8 +31,8 @@
</ui:define>
<ui:define name="info">
<h:panelGroup rendered="#{login.registrationAllowed}">
<p>No account? <a href="#{login.registrationUrl}">Register</a>.</p>
<h:panelGroup rendered="#{forms.registrationAllowed}">
<p>No account? <a href="#{forms.registrationUrl}">Register</a>.</p>
</h:panelGroup>
</ui:define>
</ui:composition>

View file

@ -4,28 +4,33 @@
<ui:param name="bodyClass" value="register" />
<ui:define name="header">Register with <strong>#{login.name}</strong></ui:define>
<ui:define name="header">Register with <strong>#{forms.name}</strong></ui:define>
<ui:define name="form">
<form action="#{login.registerAction}" method="post">
<form action="#{forms.registrationAction}" method="post">
<p class="subtitle">All fields are required</p>
<div>
<label for="name">Full name</label>
<input type="text" id="name" />
<input type="text" id="name" name="name" value="#{forms.formData['name']}" />
</div>
<div>
<label for="email">Email</label>
<input type="email" id="email" />
<input type="text" id="email" name="email" value="#{forms.formData['email']}" />
</div>
<div>
<label for="username">Username</label>
<input type="text" id="username" />
<input type="text" id="username" name="username" value="#{forms.formData['username']}" />
</div>
<div>
<label for="password">Password</label>
<input type="password" id="password" />
<input type="password" id="password" name="password" />
</div>
<div>
<label for="password-confirm">Password confirmation</label>
<input type="password" id="password-confirm" name="password-confirm" />
</div>
<ui:repeat var="p" value="#{login.hiddenProperties}">
<ui:repeat var="p" value="#{forms.hiddenProperties}">
<input name="#{p.name}" value="#{p.value}" type="hidden" />
</ui:repeat>
@ -38,6 +43,6 @@
</ui:define>
<ui:define name="info">
<p>Already have an account? <a href="realm-login.html">Log in</a>.</p>
<p>Already have an account? <a href="#{forms.loginUrl}">Log in</a>.</p>
</ui:define>
</ui:composition>

View file

@ -3,42 +3,47 @@
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Log in to #{login.name}</title>
<link href="#{login.themeConfig['styles']}" rel="stylesheet" />
<title>Log in to #{forms.name}</title>
<link href="#{forms.themeConfig['styles']}" rel="stylesheet" />
<style>
body {
background-image: url("#{login.themeConfig['background']}");
background-image: url("#{forms.themeConfig['background']}");
}
</style>
</h:head>
<h:body class="rcue-login-register #{bodyClass}">
<h:panelGroup rendered="#{not empty login.themeConfig['logo']}">
<h1><a href="#" title="Go to the home page"><img src="#{login.themeConfig['logo']}" alt="Logo" /></a></h1>
<h:panelGroup rendered="#{not empty forms.themeConfig['logo']}">
<h1><a href="#" title="Go to the home page"><img src="#{forms.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 #{login.social ? 'social' : ''} clearfix">
<div class="form-area #{forms.social ? 'social' : ''} clearfix">
<section class="app-form">
<h3>Application login area</h3>
<h:panelGroup rendered="#{not empty login.error}">
<div class="feedback error bottom-left show"><p><strong>#{login.error}</strong></p></div>
<h:panelGroup rendered="#{not empty forms.error}">
<div class="feedback error bottom-left show">
<p>
<strong>#{forms.error}</strong><br/>
#{forms.errorDetails}
</p>
</div>
</h:panelGroup>
<ui:insert name="form" />
</section>
<h:panelGroup rendered="#{login.social}">
<h:panelGroup rendered="#{forms.social}">
<section class="social-login">
<span>or</span>
<h3>Social login area</h3>
<p>Log In with</p>
<ul>
<ui:repeat var="p" value="#{login.providers}">
<ui:repeat var="p" value="#{forms.providers}">
<li><a href="#{p.loginUrl}" class="zocial #{p.id}"> <span class="text">#{p.name}</span></a></li>
</ui:repeat>
</ul>
@ -48,16 +53,16 @@
<section class="info-area">
<h3>Info area</h3>
<ui:insert name="info" />
<ul>
<li><strong>Domain:</strong> 10.0.0.1</li>
<li><strong>Zone:</strong> Live</li>
<li><strong>Appliance:</strong> Yep</li>
</ul>
<!-- <ul> -->
<!-- <li><strong>Domain:</strong> 10.0.0.1</li> -->
<!-- <li><strong>Zone:</strong> Live</li> -->
<!-- <li><strong>Appliance:</strong> Yep</li> -->
<!-- </ul> -->
</section>
</div>
</div>
<h:panelGroup rendered="#{login.themeConfig['displayPoweredBy']}">
<h:panelGroup rendered="#{forms.themeConfig['displayPoweredBy']}">
<p class="powered"><a href="#">Powered by Keycloak</a></p>
</h:panelGroup>
</div>

View file

@ -58,7 +58,7 @@
<module>integration</module>
<module>examples</module>
<module>social</module>
<module>sdk-html</module>
<module>forms</module>
<!--<module>ui</module> -->
</modules>

View file

@ -1,7 +1,5 @@
package org.keycloak.services.resources;
import java.net.URI;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
@ -22,7 +20,6 @@ public class OAuthUtil {
private static final Logger log = Logger.getLogger(OAuthUtil.class);
public final static String securityFailurePath = "/saas/securityFailure.jsp";
public final static String loginFormPath = "/sdk/login.xhtml";
public final static String oauthFormPath = "/saas/oauthGrantForm.jsp";
public static Response processAccessCode(RealmModel realm, TokenManager tokenManager, AuthenticationManager authManager,
@ -75,16 +72,22 @@ public class OAuthUtil {
public static void forwardToLoginForm(RealmModel realm, HttpRequest request, UriInfo uriInfo, String redirect,
String clientId, String scopeParam, String state) {
request.setAttribute(RealmModel.class.getName(), realm);
request.setAttribute("KEYCLOAK_LOGIN_ACTION", TokenService.processLoginUrl(uriInfo).build(realm.getId()));
request.setAttribute("KEYCLOAK_SOCIAL_LOGIN", SocialResource.redirectToProviderAuthUrl(uriInfo).build(realm.getId()));
request.setAttribute("KEYCLOAK_REGISTRATION_PAGE", URI.create("not-implemented-yet"));
request.setAttribute("KEYCLOAK_LOGIN_PAGE", Urls.realmLoginPage(uriInfo, realm.getId()));
request.setAttribute("KEYCLOAK_LOGIN_ACTION", Urls.realmLoginAction(uriInfo, realm.getId()));
request.setAttribute("KEYCLOAK_REGISTRATION_PAGE", Urls.realmRegisterPage(uriInfo, realm.getId()));
request.setAttribute("KEYCLOAK_REGISTRATION_ACTION", Urls.realmRegisterAction(uriInfo, realm.getId()));
request.setAttribute("KEYCLOAK_SOCIAL_LOGIN", Urls.socialRedirectToProviderAuth(uriInfo, realm.getId()));
// RESTEASY eats the form data, so we send via an attribute
request.setAttribute("redirect_uri", redirect);
request.setAttribute("client_id", clientId);
request.setAttribute("scope", scopeParam);
request.setAttribute("state", state);
request.forward(loginFormPath);
request.forward(Pages.loginForm);
}
public static void oauthGrantPage(RealmModel realm, HttpRequest request, UriInfo uriInfo, AccessCodeEntry accessCode,

View file

@ -0,0 +1,8 @@
package org.keycloak.services.resources;
public class Pages {
public final static String loginForm = "/sdk/login.xhtml";
public final static String registerForm = "/sdk/register.xhtml";
}

View file

@ -39,8 +39,6 @@ public class SaasService {
@Context
HttpResponse response;
protected String saasLoginPath = "/saas/saas-login.jsp";
protected String saasRegisterPath = "/saas/saas-register.jsp";
protected String adminPath = "/saas/admin/index.html";
protected AuthenticationManager authManager = new AuthenticationManager();
@ -170,7 +168,7 @@ public class SaasService {
}.call();
}
@Path("loginPage.html")
@Path("login")
@GET
@NoCache
public void loginPage() {
@ -180,7 +178,22 @@ public class SaasService {
RealmManager realmManager = new RealmManager(session);
RealmModel realm = realmManager.defaultRealm();
authManager.expireSaasIdentityCookie(uriInfo);
forwardToLoginForm(realm);
forwardToLoginForm(realm, null, null);
}
}.run();
}
@Path("registrations")
@GET
@NoCache
public void registerPage() {
new Transaction() {
@Override
protected void runImpl() {
RealmManager realmManager = new RealmManager(session);
RealmModel realm = realmManager.defaultRealm();
authManager.expireSaasIdentityCookie(uriInfo);
forwardToRegisterForm(realm, null, null);
}
}.run();
}
@ -195,7 +208,7 @@ public class SaasService {
RealmManager realmManager = new RealmManager(session);
RealmModel realm = realmManager.defaultRealm();
authManager.expireSaasIdentityCookie(uriInfo);
forwardToLoginForm(realm);
forwardToLoginForm(realm, null, null);
}
}.run();
}
@ -214,16 +227,42 @@ public class SaasService {
}.run();
}
public final static String loginFormPath = "/sdk/login.xhtml";
protected void forwardToLoginForm(RealmModel realm, String error, MultivaluedMap<String, String> formData) {
if (error != null) {
request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", error);
}
protected void forwardToLoginForm(RealmModel realm) {
if (formData != null) {
request.setAttribute("KEYCLOAK_FORM_DATA", formData);
}
forwardToForm(realm, Pages.loginForm);
}
protected void forwardToRegisterForm(RealmModel realm, String error, MultivaluedMap<String, String> formData) {
if (error != null) {
request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", error);
}
if (formData != null) {
request.setAttribute("KEYCLOAK_FORM_DATA", formData);
}
forwardToForm(realm, Pages.registerForm);
}
protected void forwardToForm(RealmModel realm, String form) {
request.setAttribute(RealmModel.class.getName(), realm);
URI action = uriInfo.getBaseUriBuilder().path(SaasService.class).path(SaasService.class, "processLogin").build();
URI register = contextRoot(uriInfo).path(saasRegisterPath).build();
request.setAttribute("KEYCLOAK_LOGIN_ACTION", action);
request.setAttribute("KEYCLOAK_REGISTRATION_PAGE", register);
request.setAttribute("KEYCLOAK_SOCIAL_LOGIN", SocialResource.redirectToProviderAuthUrl(uriInfo).build(realm.getId()));
request.forward(loginFormPath);
request.setAttribute("KEYCLOAK_LOGIN_PAGE", Urls.saasLoginPage(uriInfo));
request.setAttribute("KEYCLOAK_LOGIN_ACTION", Urls.saasLoginAction(uriInfo));
request.setAttribute("KEYCLOAK_REGISTRATION_PAGE", Urls.saasRegisterPage(uriInfo));
request.setAttribute("KEYCLOAK_REGISTRATION_ACTION", Urls.saasRegisterAction(uriInfo));
request.setAttribute("KEYCLOAK_SOCIAL_LOGIN", Urls.socialRedirectToProviderAuth(uriInfo, realm.getId()));
request.forward(form);
}
@ -246,22 +285,19 @@ public class SaasService {
UserModel user = realm.getUser(username);
if (user == null) {
logger.info("Not Authenticated! Incorrect user name");
request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", "Incorrect user name.");
forwardToLoginForm(realm);
forwardToLoginForm(realm, "Invalid username or password", formData);
return null;
}
if (!user.isEnabled()) {
logger.info("NAccount is disabled, contact admin.");
request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", "Account is disabled, contact admin.");
forwardToLoginForm(realm);
forwardToLoginForm(realm, "Account is disabled, contact admin.", formData);
return null;
}
boolean authenticated = authManager.authenticateForm(realm, user, formData);
if (!authenticated) {
logger.info("Not Authenticated! Invalid credentials");
request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", "Invalid credentials.");
forwardToLoginForm(realm);
forwardToLoginForm(realm, "Invalid username or password", formData);
return null;
}
@ -295,24 +331,24 @@ public class SaasService {
@Path("registrations")
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response processRegister(final @FormParam("name") String fullname,
final @FormParam("email") String email,
final @FormParam("username") String username,
final @FormParam("password") String password,
final @FormParam("password-confirm") String confirm) {
if (!password.equals(confirm)) {
request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", "Password confirmation doesn't match.");
request.forward(saasRegisterPath);
return null;
}
public Response processRegister(final MultivaluedMap<String, String> formData) {
return new Transaction() {
@Override
protected Response callImpl() {
RealmManager realmManager = new RealmManager(session);
RealmModel defaultRealm = realmManager.defaultRealm();
String error = validateRegistrationForm(formData);
if (error != null) {
forwardToRegisterForm(defaultRealm, error, formData);
return null;
}
UserRepresentation newUser = new UserRepresentation();
newUser.setUsername(username);
newUser.setEmail(email);
newUser.setUsername(formData.getFirst("username"));
newUser.setEmail(formData.getFirst("email"));
String fullname = formData.getFirst("name");
if (fullname != null) {
StringTokenizer tokenizer = new StringTokenizer(fullname, " ");
StringBuffer first = null;
@ -334,11 +370,11 @@ public class SaasService {
newUser.setFirstName(first.toString());
newUser.setLastName(last);
}
newUser.credential(CredentialRepresentation.PASSWORD, password);
newUser.credential(CredentialRepresentation.PASSWORD, formData.getFirst("password"));
UserModel user = registerMe(defaultRealm, newUser);
if (user == null) {
request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", "Username already exists.");
request.forward(saasRegisterPath);
forwardToRegisterForm(defaultRealm, "Username already exists.", formData);
return null;
}
@ -376,5 +412,32 @@ public class SaasService {
return user;
}
private String validateRegistrationForm(MultivaluedMap<String, String> formData) {
if (isEmpty(formData.getFirst("name"))) {
return "Please specify full name";
}
if (isEmpty(formData.getFirst("email"))) {
return "Please specify email";
}
if (isEmpty(formData.getFirst("username"))) {
return "Please specify username";
}
if (isEmpty(formData.getFirst("password"))) {
return "Please specify password";
}
if (!formData.getFirst("password").equals(formData.getFirst("password-confirm"))) {
return "Password confirmation doesn't match.";
}
return null;
}
private boolean isEmpty(String s) {
return s == null || s.length() == 0;
}
}

View file

@ -199,7 +199,8 @@ public class TokenService {
UserModel user = realm.getUser(username);
if (user == null) {
logger.error("Incorrect user name.");
request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", "Incorrect user name.");
request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", "Invalid username or password");
request.setAttribute("KEYCLOAK_FORM_DATA", formData);
OAuthUtil.forwardToLoginForm(realm, request, uriInfo, redirect, clientId, scopeParam, state);
return null;
}
@ -211,7 +212,8 @@ public class TokenService {
if (!authenticated) {
logger.error("Authentication failed");
request.setAttribute("username", username);
request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", "Invalid credentials.");
request.setAttribute("KEYCLOAK_LOGIN_ERROR_MESSAGE", "Invalid username or password");
request.setAttribute("KEYCLOAK_FORM_DATA", formData);
OAuthUtil.forwardToLoginForm(realm, request, uriInfo, redirect, clientId, scopeParam, state);
return null;
}

View file

@ -0,0 +1,45 @@
package org.keycloak.services.resources;
import java.net.URI;
import javax.ws.rs.core.UriInfo;
public class Urls {
public static URI realmLoginAction(UriInfo uriInfo, String realmId) {
return TokenService.processLoginUrl(uriInfo).build(realmId);
}
public static URI realmLoginPage(UriInfo uriInfo, String realmId) {
return uriInfo.getBaseUriBuilder().path(SaasService.class).path(SaasService.class, "processLogin").build();
}
public static URI realmRegisterAction(UriInfo uriInfo, String realmId) {
return URI.create("not-implemented-yet");
}
public static URI realmRegisterPage(UriInfo uriInfo, String realmId) {
return URI.create("not-implemented-yet");
}
public static URI saasLoginAction(UriInfo uriInfo) {
return uriInfo.getBaseUriBuilder().path(SaasService.class).path(SaasService.class, "processLogin").build();
}
public static URI saasLoginPage(UriInfo uriInfo) {
return uriInfo.getBaseUriBuilder().path(SaasService.class).path(SaasService.class, "loginPage").build();
}
public static URI saasRegisterAction(UriInfo uriInfo) {
return uriInfo.getBaseUriBuilder().path(SaasService.class).path(SaasService.class, "processRegister").build();
}
public static URI saasRegisterPage(UriInfo uriInfo) {
return uriInfo.getBaseUriBuilder().path(SaasService.class).path(SaasService.class, "registerPage").build();
}
public static URI socialRedirectToProviderAuth(UriInfo uriInfo, String realmId) {
return SocialResource.redirectToProviderAuthUrl(uriInfo).build(realmId);
}
}