Renamed sdk-html for forms and added registration form
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
@ -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>
|
|
@ -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();
|
||||
|
@ -55,20 +63,26 @@ public class LoginBean {
|
|||
HttpServletRequest request = (HttpServletRequest) ctx.getExternalContext().getRequest();
|
||||
|
||||
realm = (RealmModel) request.getAttribute(RealmModel.class.getName());
|
||||
|
||||
|
||||
if (RealmModel.DEFAULT_REALM.equals(realm.getName())) {
|
||||
name = "Keycloak";
|
||||
} else {
|
||||
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 {
|
|
@ -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" />
|
|
@ -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" />
|
Before Width: | Height: | Size: 722 B After Width: | Height: | Size: 722 B |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 513 B After Width: | Height: | Size: 513 B |
Before Width: | Height: | Size: 793 B After Width: | Height: | Size: 793 B |
Before Width: | Height: | Size: 343 B After Width: | Height: | Size: 343 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 551 B After Width: | Height: | Size: 551 B |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 77 KiB |
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
@ -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>
|
|
@ -4,31 +4,36 @@
|
|||
|
||||
<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>
|
||||
|
||||
|
||||
<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>
|
||||
|
@ -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>
|
|
@ -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>
|
2
pom.xml
|
@ -58,7 +58,7 @@
|
|||
<module>integration</module>
|
||||
<module>examples</module>
|
||||
<module>social</module>
|
||||
<module>sdk-html</module>
|
||||
<module>forms</module>
|
||||
<!--<module>ui</module> -->
|
||||
</modules>
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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";
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|