terms and conditions
This commit is contained in:
parent
3dd282e11b
commit
3f62cd9271
26 changed files with 685 additions and 210 deletions
|
@ -195,7 +195,7 @@ module.controller('UserListCtrl', function($scope, realm, User) {
|
|||
|
||||
|
||||
|
||||
module.controller('UserDetailCtrl', function($scope, realm, user, User, UserFederationInstances, $location, Dialog, Notifications) {
|
||||
module.controller('UserDetailCtrl', function($scope, realm, user, User, UserFederationInstances, RequiredActions, $location, Dialog, Notifications) {
|
||||
$scope.realm = realm;
|
||||
$scope.create = !user.id;
|
||||
$scope.editUsername = $scope.create || $scope.realm.editUsernameAllowed;
|
||||
|
@ -219,14 +219,29 @@ module.controller('UserDetailCtrl', function($scope, realm, user, User, UserFede
|
|||
}
|
||||
|
||||
$scope.changed = false; // $scope.create;
|
||||
|
||||
if (user.requiredActions) {
|
||||
for (var i = 0; i < user.requiredActions.length; i++) {
|
||||
console.log("user require action: " + user.requiredActions[i]);
|
||||
}
|
||||
}
|
||||
// ID - Name map for required actions. IDs are enum names.
|
||||
$scope.userReqActionList = [
|
||||
RequiredActions.query({id: realm.realm}, function(data) {
|
||||
$scope.userReqActionList = [];
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
console.log("listed required action: " + data[i].text);
|
||||
item = { id: data[i].id, text: data[i].text };
|
||||
$scope.userReqActionList.push(item);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
/*[
|
||||
{id: "VERIFY_EMAIL", text: "Verify Email"},
|
||||
{id: "UPDATE_PROFILE", text: "Update Profile"},
|
||||
{id: "CONFIGURE_TOTP", text: "Configure Totp"},
|
||||
{id: "UPDATE_PASSWORD", text: "Update Password"}
|
||||
];
|
||||
*/
|
||||
|
||||
$scope.$watch('user', function() {
|
||||
if (!angular.equals($scope.user, user)) {
|
||||
|
|
|
@ -186,6 +186,12 @@ module.factory('RealmAdminEvents', function($resource) {
|
|||
});
|
||||
});
|
||||
|
||||
module.factory('RequiredActions', function($resource) {
|
||||
return $resource(authUrl + '/admin/realms/:id/required-actions', {
|
||||
id : '@realm'
|
||||
});
|
||||
});
|
||||
|
||||
module.factory('RealmLDAPConnectionTester', function($resource) {
|
||||
return $resource(authUrl + '/admin/realms/:realm/testLDAPConnection');
|
||||
});
|
||||
|
|
|
@ -1,76 +1,76 @@
|
|||
<#import "template.ftl" as layout>
|
||||
<@layout.registrationLayout displayInfo=social.displayInfo; section>
|
||||
<#if section = "title">
|
||||
${msg("loginTitle",(realm.name!''))}
|
||||
<#elseif section = "header">
|
||||
${msg("loginTitleHtml",(realm.name!''))}
|
||||
<#elseif section = "form">
|
||||
<#if realm.password>
|
||||
<form id="kc-form-login" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="username" class="${properties.kcLabelClass!}"><#if !realm.registrationEmailAsUsername>${msg("usernameOrEmail")}<#else>${msg("email")}</#if></label>
|
||||
</div>
|
||||
|
||||
<div class="${properties.kcInputWrapperClass!}">
|
||||
<input id="username" class="${properties.kcInputClass!}" name="username" value="${(login.username!'')?html}" type="text" autofocus />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="password" class="${properties.kcLabelClass!}">${msg("password")}</label>
|
||||
</div>
|
||||
|
||||
<div class="${properties.kcInputWrapperClass!}">
|
||||
<input id="password" class="${properties.kcInputClass!}" name="password" type="password" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
|
||||
<#if realm.rememberMe>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<#if login.rememberMe??>
|
||||
<input id="rememberMe" name="rememberMe" type="checkbox" tabindex="3" checked> ${msg("rememberMe")}
|
||||
<#else>
|
||||
<input id="rememberMe" name="rememberMe" type="checkbox" tabindex="3"> ${msg("rememberMe")}
|
||||
</#if>
|
||||
</label>
|
||||
</div>
|
||||
</#if>
|
||||
<div class="${properties.kcFormOptionsWrapperClass!}">
|
||||
<#if realm.resetPasswordAllowed>
|
||||
<span><a href="${url.loginPasswordResetUrl}">${msg("doForgotPassword")}</a></span>
|
||||
</#if>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
|
||||
<div class="${properties.kcFormButtonsWrapperClass!}">
|
||||
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" name="login" id="kc-login" type="submit" value="${msg("doLogIn")}"/>
|
||||
<input class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonLargeClass!}" name="cancel" id="kc-cancel" type="submit" value="${msg("doCancel")}"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</#if>
|
||||
<#elseif section = "info" >
|
||||
<#if realm.password && realm.registrationAllowed>
|
||||
<div id="kc-registration">
|
||||
<span>${msg("noAccount")} <a href="${url.registrationUrl}">${msg("doRegister")}</a></span>
|
||||
</div>
|
||||
</#if>
|
||||
|
||||
<#if realm.password && social.providers??>
|
||||
<div id="kc-social-providers">
|
||||
<ul>
|
||||
<#list social.providers as p>
|
||||
<li><a href="${p.loginUrl}" id="zocial-${p.alias}" class="zocial ${p.providerId}"> <span class="text">${p.alias}</span></a></li>
|
||||
</#list>
|
||||
</ul>
|
||||
</div>
|
||||
</#if>
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
||||
<#import "template.ftl" as layout>
|
||||
<@layout.registrationLayout displayInfo=social.displayInfo; section>
|
||||
<#if section = "title">
|
||||
${msg("loginTitle",(realm.name!''))}
|
||||
<#elseif section = "header">
|
||||
${msg("loginTitleHtml",(realm.name!''))}
|
||||
<#elseif section = "form">
|
||||
<#if realm.password>
|
||||
<form id="kc-form-login" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="username" class="${properties.kcLabelClass!}"><#if !realm.registrationEmailAsUsername>${msg("usernameOrEmail")}<#else>${msg("email")}</#if></label>
|
||||
</div>
|
||||
|
||||
<div class="${properties.kcInputWrapperClass!}">
|
||||
<input id="username" class="${properties.kcInputClass!}" name="username" value="${(login.username!'')?html}" type="text" autofocus />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="password" class="${properties.kcLabelClass!}">${msg("password")}</label>
|
||||
</div>
|
||||
|
||||
<div class="${properties.kcInputWrapperClass!}">
|
||||
<input id="password" class="${properties.kcInputClass!}" name="password" type="password" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
|
||||
<#if realm.rememberMe>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<#if login.rememberMe??>
|
||||
<input id="rememberMe" name="rememberMe" type="checkbox" tabindex="3" checked> ${msg("rememberMe")}
|
||||
<#else>
|
||||
<input id="rememberMe" name="rememberMe" type="checkbox" tabindex="3"> ${msg("rememberMe")}
|
||||
</#if>
|
||||
</label>
|
||||
</div>
|
||||
</#if>
|
||||
<div class="${properties.kcFormOptionsWrapperClass!}">
|
||||
<#if realm.resetPasswordAllowed>
|
||||
<span><a href="${url.loginPasswordResetUrl}">${msg("doForgotPassword")}</a></span>
|
||||
</#if>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
|
||||
<div class="${properties.kcFormButtonsWrapperClass!}">
|
||||
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" name="login" id="kc-login" type="submit" value="${msg("doLogIn")}"/>
|
||||
<input class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonLargeClass!}" name="cancel" id="kc-cancel" type="submit" value="${msg("doCancel")}"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</#if>
|
||||
<#elseif section = "info" >
|
||||
<#if realm.password && realm.registrationAllowed>
|
||||
<div id="kc-registration">
|
||||
<span>${msg("noAccount")} <a href="${url.registrationUrl}">${msg("doRegister")}</a></span>
|
||||
</div>
|
||||
</#if>
|
||||
|
||||
<#if realm.password && social.providers??>
|
||||
<div id="kc-social-providers">
|
||||
<ul>
|
||||
<#list social.providers as p>
|
||||
<li><a href="${p.loginUrl}" id="zocial-${p.alias}" class="zocial ${p.providerId}"> <span class="text">${p.alias}</span></a></li>
|
||||
</#list>
|
||||
</ul>
|
||||
</div>
|
||||
</#if>
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
||||
|
|
|
@ -4,6 +4,8 @@ doCancel=Abbrechen
|
|||
doSubmit=Absenden
|
||||
doYes=Ja
|
||||
doNo=Nein
|
||||
doAccept=Accept
|
||||
doDecline=Decline
|
||||
doForgotPassword=Passwort vergessen?
|
||||
doClickHere=hier klicken
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ doCancel=Cancel
|
|||
doSubmit=Submit
|
||||
doYes=Yes
|
||||
doNo=No
|
||||
doAccept=Accept
|
||||
doDecline=Decline
|
||||
doForgotPassword=Forgot Password?
|
||||
doClickHere=Click here
|
||||
|
||||
|
@ -22,6 +24,8 @@ emailForgotTitle=Forgot Your Password?
|
|||
updatePasswordTitle=Update password
|
||||
codeSuccessTitle=Success code
|
||||
codeErrorTitle=Error code\: {0}
|
||||
termsTitle=Terms and Conditions
|
||||
termsTitleHtml=Terms and Conditions
|
||||
|
||||
noAccount=New user?
|
||||
username=Username
|
||||
|
|
|
@ -4,6 +4,8 @@ doCancel=Annulla
|
|||
doSubmit=Invia
|
||||
doYes=Si
|
||||
doNo=No
|
||||
doAccept=Accept
|
||||
doDecline=Decline
|
||||
doForgotPassword=Password Dimenticata?
|
||||
doClickHere=Clicca qui
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ doRegister=Cadastre-se
|
|||
doCancel=Cancelar
|
||||
doSubmit=Ok
|
||||
doYes=Sim
|
||||
doAccept=Accept
|
||||
doDecline=Decline
|
||||
doNo=N\u00E3o
|
||||
doForgotPassword=Esqueceu sua senha?
|
||||
doClickHere=Clique aqui
|
||||
|
|
29
forms/common-themes/src/main/resources/theme/base/login/terms.ftl
Executable file
29
forms/common-themes/src/main/resources/theme/base/login/terms.ftl
Executable file
|
@ -0,0 +1,29 @@
|
|||
<#import "template.ftl" as layout>
|
||||
<@layout.registrationLayout displayMessage=false; section>
|
||||
<#if section = "title">
|
||||
${msg("termsTitle")}
|
||||
<#elseif section = "header">
|
||||
${msg("termsTitleHtml")}
|
||||
<#elseif section = "form">
|
||||
<div id="kc-info-message">
|
||||
<textarea class="${properties.kcTextareaClass!}" rows="20" cols="120">
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
</textarea>
|
||||
<form class="form-actions" action="${requiredActionUrl("terms_and_conditions", "")}" method="POST">
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
|
||||
<div class="${properties.kcFormButtonsWrapperClass!}">
|
||||
<input class="${properties.kcButtonClass!} ${properties.kcButtonPrimaryClass!} ${properties.kcButtonLargeClass!}" name="accept" id="kc-login" type="submit" value="${msg("doAccept")}"/>
|
||||
<input class="${properties.kcButtonClass!} ${properties.kcButtonDefaultClass!} ${properties.kcButtonLargeClass!}" name="cancel" id="kc-cancel" type="submit" value="${msg("doDecline")}"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</#if>
|
||||
</@layout.registrationLayout>
|
|
@ -2,6 +2,7 @@ package org.keycloak.login;
|
|||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
|
@ -24,6 +25,8 @@ public interface LoginFormsProvider extends Provider {
|
|||
|
||||
public Response createResponse(UserModel.RequiredAction action);
|
||||
|
||||
Response createForm(String form, Map<String, Object> attributes);
|
||||
|
||||
public Response createLogin();
|
||||
|
||||
public Response createPasswordReset();
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.keycloak.login.freemarker.model.OAuthGrantBean;
|
|||
import org.keycloak.login.freemarker.model.ProfileBean;
|
||||
import org.keycloak.login.freemarker.model.RealmBean;
|
||||
import org.keycloak.login.freemarker.model.RegisterBean;
|
||||
import org.keycloak.login.freemarker.model.RequiredActionUrlFormatterMethod;
|
||||
import org.keycloak.login.freemarker.model.TotpBean;
|
||||
import org.keycloak.login.freemarker.model.UrlBean;
|
||||
import org.keycloak.models.ClientModel;
|
||||
|
@ -205,6 +206,7 @@ import java.util.concurrent.TimeUnit;
|
|||
uriBuilder.replaceQuery(null);
|
||||
}
|
||||
URI baseUri = uriBuilder.build();
|
||||
attributes.put("requiredActionUrl", new RequiredActionUrlFormatterMethod(realm, baseUri));
|
||||
|
||||
if (realm != null) {
|
||||
attributes.put("realm", new RealmBean(realm));
|
||||
|
@ -272,6 +274,98 @@ import java.util.concurrent.TimeUnit;
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response createForm(String form, Map<String, Object> attributes) {
|
||||
RealmModel realm = session.getContext().getRealm();
|
||||
ClientModel client = session.getContext().getClient();
|
||||
UriInfo uriInfo = session.getContext().getUri();
|
||||
|
||||
MultivaluedMap<String, String> queryParameterMap = queryParams != null ? queryParams : new MultivaluedMapImpl<String, String>();
|
||||
|
||||
String requestURI = uriInfo.getBaseUri().getPath();
|
||||
UriBuilder uriBuilder = UriBuilder.fromUri(requestURI);
|
||||
|
||||
for (String k : queryParameterMap.keySet()) {
|
||||
|
||||
Object[] objects = queryParameterMap.get(k).toArray();
|
||||
if (objects.length == 1 && objects[0] == null) continue; //
|
||||
uriBuilder.replaceQueryParam(k, objects);
|
||||
}
|
||||
if (accessCode != null) {
|
||||
uriBuilder.replaceQueryParam(OAuth2Constants.CODE, accessCode);
|
||||
}
|
||||
URI baseUri = uriBuilder.build();
|
||||
|
||||
ThemeProvider themeProvider = session.getProvider(ThemeProvider.class, "extending");
|
||||
Theme theme;
|
||||
try {
|
||||
theme = themeProvider.getTheme(realm.getLoginTheme(), Theme.Type.LOGIN);
|
||||
} catch (IOException e) {
|
||||
logger.error("Failed to create theme", e);
|
||||
return Response.serverError().build();
|
||||
}
|
||||
|
||||
try {
|
||||
attributes.put("properties", theme.getProperties());
|
||||
} catch (IOException e) {
|
||||
logger.warn("Failed to load properties", e);
|
||||
}
|
||||
|
||||
Properties messagesBundle;
|
||||
Locale locale = LocaleHelper.getLocale(realm, user, uriInfo, session.getContext().getRequestHeaders());
|
||||
try {
|
||||
messagesBundle = theme.getMessages(locale);
|
||||
attributes.put("msg", new MessageFormatterMethod(locale, messagesBundle));
|
||||
} catch (IOException e) {
|
||||
logger.warn("Failed to load messages", e);
|
||||
messagesBundle = new Properties();
|
||||
}
|
||||
|
||||
MessagesPerFieldBean messagesPerField = new MessagesPerFieldBean();
|
||||
if (messages != null) {
|
||||
MessageBean wholeMessage = new MessageBean(null, messageType);
|
||||
for (FormMessage message : this.messages) {
|
||||
String formattedMessageText = formatMessage(message, messagesBundle, locale);
|
||||
if (formattedMessageText != null) {
|
||||
wholeMessage.appendSummaryLine(formattedMessageText);
|
||||
messagesPerField.addMessage(message.getField(), formattedMessageText, messageType);
|
||||
}
|
||||
}
|
||||
attributes.put("message", wholeMessage);
|
||||
}
|
||||
attributes.put("messagesPerField", messagesPerField);
|
||||
|
||||
if (status == null) {
|
||||
status = Response.Status.OK;
|
||||
}
|
||||
|
||||
if (realm != null) {
|
||||
attributes.put("realm", new RealmBean(realm));
|
||||
attributes.put("social", new IdentityProviderBean(realm, baseUri, uriInfo));
|
||||
attributes.put("url", new UrlBean(realm, theme, baseUri, this.actionUri));
|
||||
attributes.put("requiredActionUrl", new RequiredActionUrlFormatterMethod(realm, baseUri));
|
||||
|
||||
if (realm.isInternationalizationEnabled()) {
|
||||
UriBuilder b = UriBuilder.fromUri(baseUri).path(uriInfo.getPath());
|
||||
attributes.put("locale", new LocaleBean(realm, locale, b, messagesBundle));
|
||||
}
|
||||
}
|
||||
try {
|
||||
String result = freeMarker.processTemplate(attributes, form, theme);
|
||||
Response.ResponseBuilder builder = Response.status(status).type(MediaType.TEXT_HTML).entity(result);
|
||||
BrowserSecurityHeaderSetup.headers(builder, realm);
|
||||
for (Map.Entry<String, String> entry : httpResponseHeaders.entrySet()) {
|
||||
builder.header(entry.getKey(), entry.getValue());
|
||||
}
|
||||
LocaleHelper.updateLocaleCookie(builder, locale, realm, uriInfo, Urls.localeCookiePath(baseUri, realm.getName()));
|
||||
return builder.build();
|
||||
} catch (FreeMarkerException e) {
|
||||
logger.error("Failed to process template", e);
|
||||
return Response.serverError().build();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Response createLogin() {
|
||||
return createResponse(LoginFormsPages.LOGIN);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package org.keycloak.login.freemarker.model;
|
||||
|
||||
import freemarker.template.TemplateMethodModelEx;
|
||||
import freemarker.template.TemplateModelException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.services.Urls;
|
||||
|
||||
import java.net.URI;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class RequiredActionUrlFormatterMethod implements TemplateMethodModelEx {
|
||||
private final String realm;
|
||||
private final URI baseUri;
|
||||
|
||||
public RequiredActionUrlFormatterMethod(RealmModel realm, URI baseUri) {
|
||||
this.realm = realm.getName();
|
||||
this.baseUri = baseUri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object exec(List list) throws TemplateModelException {
|
||||
String action = list.get(0).toString();
|
||||
String relativePath = list.get(1).toString();
|
||||
String url = Urls.requiredActionBase(baseUri).path(relativePath).build(realm, action).toString();
|
||||
return url;
|
||||
}
|
||||
}
|
|
@ -1,102 +1,102 @@
|
|||
/*
|
||||
* 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.login.freemarker.model;
|
||||
|
||||
import org.keycloak.freemarker.Theme;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.services.Urls;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class UrlBean {
|
||||
|
||||
private final URI actionuri;
|
||||
private URI baseURI;
|
||||
private Theme theme;
|
||||
private String realm;
|
||||
|
||||
public UrlBean(RealmModel realm, Theme theme, URI baseURI, URI actionUri) {
|
||||
this.realm = realm.getName();
|
||||
this.theme = theme;
|
||||
this.baseURI = baseURI;
|
||||
this.actionuri = actionUri;
|
||||
}
|
||||
|
||||
public String getLoginAction() {
|
||||
if (this.actionuri != null) {
|
||||
return this.actionuri.toString();
|
||||
}
|
||||
return Urls.realmLoginAction(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getLoginUrl() {
|
||||
return Urls.realmLoginPage(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getRegistrationAction() {
|
||||
return Urls.realmRegisterAction(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getRegistrationUrl() {
|
||||
return Urls.realmRegisterPage(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getLoginUpdatePasswordUrl() {
|
||||
return Urls.loginActionUpdatePassword(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getLoginUpdateTotpUrl() {
|
||||
return Urls.loginActionUpdateTotp(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getLoginUpdateProfileUrl() {
|
||||
return Urls.loginActionUpdateProfile(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getLoginPasswordResetUrl() {
|
||||
return Urls.loginPasswordReset(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getLoginUsernameReminderUrl() {
|
||||
return Urls.loginUsernameReminder(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getLoginEmailVerificationUrl() {
|
||||
return Urls.loginActionEmailVerification(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getOauthAction() {
|
||||
if (this.actionuri != null) {
|
||||
return this.actionuri.getPath();
|
||||
}
|
||||
|
||||
return Urls.realmOauthAction(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getResourcesPath() {
|
||||
URI uri = Urls.themeRoot(baseURI);
|
||||
return uri.getPath() + "/" + theme.getType().toString().toLowerCase() +"/" + theme.getName();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.login.freemarker.model;
|
||||
|
||||
import org.keycloak.freemarker.Theme;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.services.Urls;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class UrlBean {
|
||||
|
||||
private final URI actionuri;
|
||||
private URI baseURI;
|
||||
private Theme theme;
|
||||
private String realm;
|
||||
|
||||
public UrlBean(RealmModel realm, Theme theme, URI baseURI, URI actionUri) {
|
||||
this.realm = realm.getName();
|
||||
this.theme = theme;
|
||||
this.baseURI = baseURI;
|
||||
this.actionuri = actionUri;
|
||||
}
|
||||
|
||||
public String getLoginAction() {
|
||||
if (this.actionuri != null) {
|
||||
return this.actionuri.toString();
|
||||
}
|
||||
return Urls.realmLoginAction(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getLoginUrl() {
|
||||
return Urls.realmLoginPage(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getRegistrationAction() {
|
||||
return Urls.realmRegisterAction(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getRegistrationUrl() {
|
||||
return Urls.realmRegisterPage(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getLoginUpdatePasswordUrl() {
|
||||
return Urls.loginActionUpdatePassword(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getLoginUpdateTotpUrl() {
|
||||
return Urls.loginActionUpdateTotp(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getLoginUpdateProfileUrl() {
|
||||
return Urls.loginActionUpdateProfile(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getLoginPasswordResetUrl() {
|
||||
return Urls.loginPasswordReset(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getLoginUsernameReminderUrl() {
|
||||
return Urls.loginUsernameReminder(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getLoginEmailVerificationUrl() {
|
||||
return Urls.loginActionEmailVerification(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getOauthAction() {
|
||||
if (this.actionuri != null) {
|
||||
return this.actionuri.getPath();
|
||||
}
|
||||
|
||||
return Urls.realmOauthAction(baseURI, realm).toString();
|
||||
}
|
||||
|
||||
public String getResourcesPath() {
|
||||
URI uri = Urls.themeRoot(baseURI);
|
||||
return uri.getPath() + "/" + theme.getType().toString().toLowerCase() +"/" + theme.getName();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,8 @@ public class ModelToRepresentation {
|
|||
rep.setFederationLink(user.getFederationLink());
|
||||
|
||||
List<String> reqActions = new ArrayList<String>();
|
||||
for (String ra : user.getRequiredActions()){
|
||||
Set<String> requiredActions = user.getRequiredActions();
|
||||
for (String ra : requiredActions){
|
||||
reqActions.add(ra);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,4 +7,5 @@ import org.keycloak.provider.ProviderFactory;
|
|||
* @version $Revision: 1 $
|
||||
*/
|
||||
public interface RequiredActionFactory extends ProviderFactory<RequiredActionProvider> {
|
||||
String getDisplayText();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
package org.keycloak.authentication.actions;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.Version;
|
||||
import org.keycloak.authentication.RequiredActionContext;
|
||||
import org.keycloak.authentication.RequiredActionFactory;
|
||||
import org.keycloak.authentication.RequiredActionProvider;
|
||||
import org.keycloak.events.Errors;
|
||||
import org.keycloak.freemarker.BrowserSecurityHeaderSetup;
|
||||
import org.keycloak.freemarker.FreeMarkerException;
|
||||
import org.keycloak.freemarker.FreeMarkerUtil;
|
||||
import org.keycloak.freemarker.Theme;
|
||||
import org.keycloak.freemarker.ThemeProvider;
|
||||
import org.keycloak.login.LoginFormsProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.protocol.LoginProtocol;
|
||||
import org.keycloak.services.Urls;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
import org.keycloak.services.managers.ClientSessionCode;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class TermsAndConditions implements RequiredActionProvider, RequiredActionFactory {
|
||||
|
||||
public static final String PROVIDER_ID = "terms_and_conditions";
|
||||
|
||||
public static class Resource {
|
||||
|
||||
public Resource(RequiredActionContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
protected RequiredActionContext context;
|
||||
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
public Response agree(final MultivaluedMap<String, String> formData) throws URISyntaxException, IOException, FreeMarkerException {
|
||||
if (formData.containsKey("cancel")) {
|
||||
LoginProtocol protocol = context.getSession().getProvider(LoginProtocol.class, context.getClientSession().getAuthMethod());
|
||||
protocol.setRealm(context.getRealm())
|
||||
.setHttpHeaders(context.getHttpRequest().getHttpHeaders())
|
||||
.setUriInfo(context.getUriInfo());
|
||||
context.getEvent().error(Errors.REJECTED_BY_USER);
|
||||
return protocol.consentDenied(context.getClientSession());
|
||||
}
|
||||
context.getUser().removeRequiredAction(PROVIDER_ID);
|
||||
return AuthenticationManager.nextActionAfterAuthentication(context.getSession(), context.getUserSession(), context.getClientSession(), context.getConnection(), context.getHttpRequest(), context.getUriInfo(), context.getEvent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequiredActionProvider create(KeycloakSession session) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInit(KeycloakSessionFactory factory) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evaluateTriggers(RequiredActionContext context) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response invokeRequiredAction(RequiredActionContext context) {
|
||||
return context.getSession().getProvider(LoginFormsProvider.class)
|
||||
.setClientSessionCode(new ClientSessionCode(context.getRealm(), context.getClientSession()).getCode())
|
||||
.createForm("terms.ftl", new HashMap<String, Object>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object jaxrsService(RequiredActionContext context) {
|
||||
return new Resource(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayText() {
|
||||
return "Terms and Conditions";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
}
|
|
@ -86,6 +86,12 @@ public class UpdatePassword implements RequiredActionProvider, RequiredActionFac
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayText() {
|
||||
return "Update Password";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return UserModel.RequiredAction.UPDATE_PASSWORD.name();
|
||||
|
|
|
@ -68,6 +68,12 @@ public class UpdateProfile implements RequiredActionProvider, RequiredActionFact
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayText() {
|
||||
return "Update Profile";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return UserModel.RequiredAction.UPDATE_PROFILE.name();
|
||||
|
|
|
@ -76,6 +76,12 @@ public class UpdateTotp implements RequiredActionProvider, RequiredActionFactory
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayText() {
|
||||
return "Configure Totp";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return UserModel.RequiredAction.CONFIGURE_TOTP.name();
|
||||
|
|
|
@ -96,6 +96,12 @@ public class VerifyEmail implements RequiredActionProvider, RequiredActionFactor
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayText() {
|
||||
return "Verify Email";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return UserModel.RequiredAction.VERIFY_EMAIL.name();
|
||||
|
|
|
@ -128,15 +128,20 @@ public class Urls {
|
|||
}
|
||||
|
||||
public static URI loginActionUpdatePassword(URI baseUri, String realmId) {
|
||||
return requiredActionsBase(baseUri).path(LoginActionsService.class, "updatePassword").build(realmId);
|
||||
return loginActionsBase(baseUri).path(LoginActionsService.class, "updatePassword").build(realmId);
|
||||
}
|
||||
|
||||
public static URI loginActionUpdateTotp(URI baseUri, String realmId) {
|
||||
return requiredActionsBase(baseUri).path(LoginActionsService.class, "updateTotp").build(realmId);
|
||||
return loginActionsBase(baseUri).path(LoginActionsService.class, "updateTotp").build(realmId);
|
||||
}
|
||||
|
||||
public static UriBuilder requiredActionBase(URI baseUri) {
|
||||
return loginActionsBase(baseUri).path(LoginActionsService.class, "requiredAction");
|
||||
}
|
||||
|
||||
|
||||
public static URI loginActionUpdateProfile(URI baseUri, String realmId) {
|
||||
return requiredActionsBase(baseUri).path(LoginActionsService.class, "updateProfile").build(realmId);
|
||||
return loginActionsBase(baseUri).path(LoginActionsService.class, "updateProfile").build(realmId);
|
||||
}
|
||||
|
||||
public static URI loginActionEmailVerification(URI baseUri, String realmId) {
|
||||
|
@ -144,7 +149,7 @@ public class Urls {
|
|||
}
|
||||
|
||||
public static UriBuilder loginActionEmailVerificationBuilder(URI baseUri) {
|
||||
return requiredActionsBase(baseUri).path(LoginActionsService.class, "emailVerification");
|
||||
return loginActionsBase(baseUri).path(LoginActionsService.class, "emailVerification");
|
||||
}
|
||||
|
||||
public static URI loginPasswordReset(URI baseUri, String realmId) {
|
||||
|
@ -152,7 +157,7 @@ public class Urls {
|
|||
}
|
||||
|
||||
public static UriBuilder loginPasswordResetBuilder(URI baseUri) {
|
||||
return requiredActionsBase(baseUri).path(LoginActionsService.class, "passwordReset");
|
||||
return loginActionsBase(baseUri).path(LoginActionsService.class, "passwordReset");
|
||||
}
|
||||
|
||||
public static URI loginUsernameReminder(URI baseUri, String realmId) {
|
||||
|
@ -160,7 +165,7 @@ public class Urls {
|
|||
}
|
||||
|
||||
public static UriBuilder loginUsernameReminderBuilder(URI baseUri) {
|
||||
return requiredActionsBase(baseUri).path(LoginActionsService.class, "usernameReminder");
|
||||
return loginActionsBase(baseUri).path(LoginActionsService.class, "usernameReminder");
|
||||
}
|
||||
|
||||
public static String realmIssuer(URI baseUri, String realmId) {
|
||||
|
@ -172,11 +177,11 @@ public class Urls {
|
|||
}
|
||||
|
||||
public static URI realmLoginAction(URI baseUri, String realmId) {
|
||||
return requiredActionsBase(baseUri).path(LoginActionsService.class, "processLogin").build(realmId);
|
||||
return loginActionsBase(baseUri).path(LoginActionsService.class, "processLogin").build(realmId);
|
||||
}
|
||||
|
||||
public static URI realmLoginPage(URI baseUri, String realmId) {
|
||||
return requiredActionsBase(baseUri).path(LoginActionsService.class, "loginPage").build(realmId);
|
||||
return loginActionsBase(baseUri).path(LoginActionsService.class, "loginPage").build(realmId);
|
||||
}
|
||||
|
||||
private static UriBuilder realmLogout(URI baseUri) {
|
||||
|
@ -184,11 +189,11 @@ public class Urls {
|
|||
}
|
||||
|
||||
public static URI realmRegisterAction(URI baseUri, String realmId) {
|
||||
return requiredActionsBase(baseUri).path(LoginActionsService.class, "processRegister").build(realmId);
|
||||
return loginActionsBase(baseUri).path(LoginActionsService.class, "processRegister").build(realmId);
|
||||
}
|
||||
|
||||
public static URI realmRegisterPage(URI baseUri, String realmId) {
|
||||
return requiredActionsBase(baseUri).path(LoginActionsService.class, "registerPage").build(realmId);
|
||||
return loginActionsBase(baseUri).path(LoginActionsService.class, "registerPage").build(realmId);
|
||||
}
|
||||
|
||||
public static URI realmInstalledAppUrnCallback(URI baseUri, String realmId) {
|
||||
|
@ -196,7 +201,7 @@ public class Urls {
|
|||
}
|
||||
|
||||
public static URI realmOauthAction(URI baseUri, String realmId) {
|
||||
return requiredActionsBase(baseUri).path(LoginActionsService.class, "processConsent").build(realmId);
|
||||
return loginActionsBase(baseUri).path(LoginActionsService.class, "processConsent").build(realmId);
|
||||
}
|
||||
|
||||
public static String localeCookiePath(URI baseUri, String realmName){
|
||||
|
@ -207,7 +212,7 @@ public class Urls {
|
|||
return themeBase(baseUri).path(Version.RESOURCES_VERSION).build();
|
||||
}
|
||||
|
||||
private static UriBuilder requiredActionsBase(URI baseUri) {
|
||||
private static UriBuilder loginActionsBase(URI baseUri) {
|
||||
return realmBase(baseUri).path(RealmsResource.class, "getLoginActionsService");
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@ import org.jboss.logging.Logger;
|
|||
import org.jboss.resteasy.spi.HttpRequest;
|
||||
import org.keycloak.ClientConnection;
|
||||
import org.keycloak.authentication.AuthenticationProcessor;
|
||||
import org.keycloak.authentication.RequiredActionContext;
|
||||
import org.keycloak.authentication.RequiredActionProvider;
|
||||
import org.keycloak.email.EmailException;
|
||||
import org.keycloak.email.EmailProvider;
|
||||
import org.keycloak.events.Details;
|
||||
|
@ -67,7 +69,9 @@ import javax.ws.rs.Consumes;
|
|||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.Cookie;
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
|
@ -303,12 +307,8 @@ public class LoginActionsService {
|
|||
event.detail(Details.CODE_ID, clientSession.getId());
|
||||
|
||||
if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE.name()) || clientSession.getUserSession() != null) {
|
||||
clientCode.setAction(ClientSessionModel.Action.AUTHENTICATE.name());
|
||||
event.client(clientSession.getClient()).error(Errors.EXPIRED_CODE);
|
||||
return session.getProvider(LoginFormsProvider.class)
|
||||
.setError(Messages.EXPIRED_CODE)
|
||||
.setClientSessionCode(clientCode.getCode())
|
||||
.createLogin();
|
||||
return ErrorPage.error(session, Messages.EXPIRED_CODE);
|
||||
}
|
||||
|
||||
ClientModel client = clientSession.getClient();
|
||||
|
@ -685,11 +685,11 @@ public class LoginActionsService {
|
|||
}
|
||||
event.session(userSession);
|
||||
|
||||
LoginProtocol protocol = session.getProvider(LoginProtocol.class, clientSession.getAuthMethod());
|
||||
protocol.setRealm(realm)
|
||||
.setHttpHeaders(headers)
|
||||
.setUriInfo(uriInfo);
|
||||
if (formData.containsKey("cancel")) {
|
||||
LoginProtocol protocol = session.getProvider(LoginProtocol.class, clientSession.getAuthMethod());
|
||||
protocol.setRealm(realm)
|
||||
.setHttpHeaders(headers)
|
||||
.setUriInfo(uriInfo);
|
||||
event.error(Errors.REJECTED_BY_USER);
|
||||
return protocol.consentDenied(clientSession);
|
||||
}
|
||||
|
@ -1075,4 +1075,111 @@ public class LoginActionsService {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Path("required-actions/{action}")
|
||||
public Object requiredAction(@QueryParam("code") String code,
|
||||
@PathParam("action") String action) {
|
||||
event.event(EventType.LOGIN);
|
||||
if (!checkSsl()) {
|
||||
event.error(Errors.SSL_REQUIRED);
|
||||
throw new WebApplicationException(ErrorPage.error(session, Messages.HTTPS_REQUIRED));
|
||||
}
|
||||
|
||||
if (!realm.isEnabled()) {
|
||||
event.error(Errors.REALM_DISABLED);
|
||||
return ErrorPage.error(session, Messages.REALM_NOT_ENABLED);
|
||||
}
|
||||
ClientSessionCode clientCode = ClientSessionCode.parse(code, session, realm);
|
||||
if (clientCode == null) {
|
||||
event.error(Errors.INVALID_CODE);
|
||||
throw new WebApplicationException(ErrorPage.error(session, Messages.INVALID_CODE));
|
||||
}
|
||||
|
||||
final ClientSessionModel clientSession = clientCode.getClientSession();
|
||||
event.detail(Details.CODE_ID, clientSession.getId());
|
||||
|
||||
/*
|
||||
if (!clientCode.isValid(ClientSessionModel.Action.AUTHENTICATE.name()) || clientSession.getUserSession() != null) {
|
||||
event.client(clientSession.getClient()).error(Errors.EXPIRED_CODE);
|
||||
throw new WebApplicationException(ErrorPage.error(session, Messages.EXPIRED_CODE));
|
||||
}
|
||||
*/
|
||||
|
||||
ClientModel client = clientSession.getClient();
|
||||
if (client == null) {
|
||||
event.error(Errors.CLIENT_NOT_FOUND);
|
||||
throw new WebApplicationException( ErrorPage.error(session, Messages.UNKNOWN_LOGIN_REQUESTER));
|
||||
}
|
||||
session.getContext().setClient(client);
|
||||
|
||||
if (!client.isEnabled()) {
|
||||
event.error(Errors.CLIENT_NOT_FOUND);
|
||||
throw new WebApplicationException( ErrorPage.error(session, Messages.LOGIN_REQUESTER_NOT_ENABLED));
|
||||
}
|
||||
|
||||
if (action == null) {
|
||||
logger.error("required action was null");
|
||||
event.error(Errors.INVALID_CODE);
|
||||
throw new WebApplicationException(ErrorPage.error(session, Messages.INVALID_CODE));
|
||||
|
||||
}
|
||||
|
||||
RequiredActionProvider provider = session.getProvider(RequiredActionProvider.class, action);
|
||||
if (provider == null) {
|
||||
logger.error("required action provider was null");
|
||||
event.error(Errors.INVALID_CODE);
|
||||
throw new WebApplicationException(ErrorPage.error(session, Messages.INVALID_CODE));
|
||||
}
|
||||
RequiredActionContext context = new RequiredActionContext() {
|
||||
@Override
|
||||
public EventBuilder getEvent() {
|
||||
return event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserModel getUser() {
|
||||
return getUserSession().getUser();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RealmModel getRealm() {
|
||||
return realm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientSessionModel getClientSession() {
|
||||
return clientSession;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserSessionModel getUserSession() {
|
||||
return clientSession.getUserSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientConnection getConnection() {
|
||||
return clientConnection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UriInfo getUriInfo() {
|
||||
return uriInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeycloakSession getSession() {
|
||||
return session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpRequest getHttpRequest() {
|
||||
return request;
|
||||
}
|
||||
};
|
||||
return provider.jaxrsService(context);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.jboss.logging.Logger;
|
|||
import org.jboss.resteasy.spi.NotFoundException;
|
||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
import org.keycloak.ClientConnection;
|
||||
import org.keycloak.authentication.RequiredActionProvider;
|
||||
import org.keycloak.events.EventBuilder;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.Constants;
|
||||
|
|
|
@ -5,6 +5,8 @@ import org.jboss.resteasy.annotations.cache.NoCache;
|
|||
import org.jboss.resteasy.spi.NotFoundException;
|
||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
import org.keycloak.ClientConnection;
|
||||
import org.keycloak.authentication.RequiredActionFactory;
|
||||
import org.keycloak.authentication.RequiredActionProvider;
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.EventQuery;
|
||||
import org.keycloak.events.EventStoreProvider;
|
||||
|
@ -24,6 +26,7 @@ import org.keycloak.models.cache.CacheUserProvider;
|
|||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
import org.keycloak.protocol.oidc.TokenManager;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.representations.adapters.action.GlobalRequestResult;
|
||||
import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
|
@ -552,4 +555,19 @@ public class RealmAdminResource {
|
|||
public IdentityProvidersResource getIdentityProviderResource() {
|
||||
return new IdentityProvidersResource(realm, session, this.auth, adminEvent);
|
||||
}
|
||||
|
||||
@Path("required-actions")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public List<Map<String, String>> getRequiredActions() {
|
||||
List<Map<String, String>> list = new LinkedList<>();
|
||||
for (ProviderFactory factory : session.getKeycloakSessionFactory().getProviderFactories(RequiredActionProvider.class)) {
|
||||
RequiredActionFactory actionFactory = (RequiredActionFactory)factory;
|
||||
Map<String, String> data = new HashMap<>();
|
||||
data.put("id", actionFactory.getId());
|
||||
data.put("text", actionFactory.getDisplayText());
|
||||
list.add(data);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ import org.jboss.resteasy.annotations.cache.NoCache;
|
|||
import org.jboss.resteasy.spi.BadRequestException;
|
||||
import org.jboss.resteasy.spi.NotFoundException;
|
||||
import org.keycloak.ClientConnection;
|
||||
import org.keycloak.authentication.RequiredActionFactory;
|
||||
import org.keycloak.authentication.RequiredActionProvider;
|
||||
import org.keycloak.email.EmailException;
|
||||
import org.keycloak.email.EmailProvider;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
|
@ -27,6 +29,7 @@ import org.keycloak.models.utils.RepresentationToModel;
|
|||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.protocol.oidc.TokenManager;
|
||||
import org.keycloak.protocol.oidc.utils.RedirectUtils;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.representations.idm.ClientMappingsRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.representations.idm.FederatedIdentityRepresentation;
|
||||
|
@ -200,11 +203,15 @@ public class UsersResource {
|
|||
List<String> reqActions = rep.getRequiredActions();
|
||||
|
||||
if (reqActions != null) {
|
||||
for (UserModel.RequiredAction ra : UserModel.RequiredAction.values()) {
|
||||
if (reqActions.contains(ra.name())) {
|
||||
user.addRequiredAction(ra);
|
||||
Set<String> allActions = new HashSet<>();
|
||||
for (ProviderFactory factory : session.getKeycloakSessionFactory().getProviderFactories(RequiredActionProvider.class)) {
|
||||
allActions.add(factory.getId());
|
||||
}
|
||||
for (String action : allActions) {
|
||||
if (reqActions.contains(action)) {
|
||||
user.addRequiredAction(action);
|
||||
} else {
|
||||
user.removeRequiredAction(ra);
|
||||
user.removeRequiredAction(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
org.keycloak.authentication.actions.UpdatePassword
|
||||
org.keycloak.authentication.actions.UpdateProfile
|
||||
org.keycloak.authentication.actions.UpdateTotp
|
||||
org.keycloak.authentication.actions.VerifyEmail
|
||||
org.keycloak.authentication.actions.VerifyEmail
|
||||
org.keycloak.authentication.actions.TermsAndConditions
|
|
@ -40,6 +40,7 @@ import org.keycloak.testsuite.AssertEvents;
|
|||
import org.keycloak.testsuite.OAuthClient;
|
||||
import org.keycloak.testsuite.pages.AppPage;
|
||||
import org.keycloak.testsuite.pages.AppPage.RequestType;
|
||||
import org.keycloak.testsuite.pages.ErrorPage;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
import org.keycloak.testsuite.pages.LoginPasswordUpdatePage;
|
||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
||||
|
@ -98,6 +99,9 @@ public class LoginTest {
|
|||
|
||||
@WebResource
|
||||
protected LoginPage loginPage;
|
||||
|
||||
@WebResource
|
||||
protected ErrorPage errorPage;
|
||||
|
||||
@WebResource
|
||||
protected LoginPasswordUpdatePage updatePasswordPage;
|
||||
|
@ -424,8 +428,10 @@ public class LoginTest {
|
|||
Time.setOffset(5000);
|
||||
loginPage.login("login@test.com", "password");
|
||||
|
||||
loginPage.assertCurrent();
|
||||
Assert.assertEquals("Login timeout. Please login again.", loginPage.getError());
|
||||
//loginPage.assertCurrent();
|
||||
errorPage.assertCurrent();
|
||||
|
||||
//Assert.assertEquals("Login timeout. Please login again.", loginPage.getError());
|
||||
|
||||
events.expectLogin().user((String) null).session((String) null).error("expired_code").clearDetails().detail(Details.CODE_ID, AssertEvents.isCodeId()).assertEvent();
|
||||
|
||||
|
|
Loading…
Reference in a new issue