reg/account custom attributes
This commit is contained in:
parent
5a37754b62
commit
33520e9fec
12 changed files with 196 additions and 3 deletions
|
@ -3,6 +3,8 @@ package org.keycloak.account.freemarker.model;
|
|||
import org.keycloak.models.UserModel;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
|
@ -11,10 +13,20 @@ public class AccountBean {
|
|||
|
||||
private final UserModel user;
|
||||
private final MultivaluedMap<String, String> profileFormData;
|
||||
private final Map<String, String> attributes = new HashMap<>();
|
||||
|
||||
public AccountBean(UserModel user, MultivaluedMap<String, String> profileFormData) {
|
||||
this.user = user;
|
||||
this.profileFormData = profileFormData;
|
||||
attributes.putAll(user.getAttributes());
|
||||
if (profileFormData != null) {
|
||||
for (String key : profileFormData.keySet()) {
|
||||
if (key.startsWith("user.attributes.")) {
|
||||
String attribute = key.substring("user.attributes.".length());
|
||||
attributes.put(attribute, profileFormData.getFirst(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
|
@ -33,4 +45,8 @@ public class AccountBean {
|
|||
return profileFormData != null ? profileFormData.getFirst("email") :user.getEmail();
|
||||
}
|
||||
|
||||
public Map<String, String> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -55,6 +55,52 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-2 col-md-2">
|
||||
<label for="user.attributes.street" class="control-label">${rb.street}</label>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-10 col-md-10">
|
||||
<input type="text" class="form-control" id="user.attributes.street" name="user.attributes.street" value="${(account.attributes.street!'')?html}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-2 col-md-2">
|
||||
<label for="user.attributes.locality" class="control-label">${rb.locality}</label>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-10 col-md-10">
|
||||
<input type="text" class="form-control" id="user.attributes.locality" name="user.attributes.locality" value="${(account.attributes.locality!'')?html}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-2 col-md-2">
|
||||
<label for="user.attributes.region" class="control-label">${rb.region}</label>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-10 col-md-10">
|
||||
<input type="text" class="form-control" id="user.attributes.region" name="user.attributes.region" value="${(account.attributes.region!'')?html}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-2 col-md-2">
|
||||
<label for="user.attributes.postal_code" class="control-label">${rb.postal_code}</label>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-10 col-md-10">
|
||||
<input type="text" class="form-control" id="user.attributes.postal_code" name="user.attributes.postal_code" value="${(account.attributes.postal_code!'')?html}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-2 col-md-2">
|
||||
<label for="user.attributes.country" class="control-label">${rb.country}</label>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-10 col-md-10">
|
||||
<input type="text" class="form-control" id="user.attributes.country" name="user.attributes.country" value="${(account.attributes.country!'')?html}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div id="kc-form-buttons" class="col-md-offset-2 col-md-10 submit">
|
||||
<div class="">
|
||||
|
|
|
@ -8,6 +8,11 @@ passwordConfirm=Confirmation
|
|||
passwordNew=New Password
|
||||
successHeader=Success!
|
||||
username=Username
|
||||
street=Street
|
||||
locality=City or Locality
|
||||
region=State, Province, or Region
|
||||
postal_code=Zip or Postal code
|
||||
country=Country
|
||||
|
||||
missingFirstName=Please specify first name
|
||||
invalidEmail=Invalid email address
|
||||
|
|
|
@ -179,12 +179,15 @@ module.controller('UserListCtrl', function($scope, realm, User) {
|
|||
|
||||
module.controller('UserDetailCtrl', function($scope, realm, user, User, UserFederationInstances, $location, Dialog, Notifications) {
|
||||
$scope.realm = realm;
|
||||
$scope.user = angular.copy(user);
|
||||
$scope.create = !user.username;
|
||||
|
||||
if ($scope.create) {
|
||||
$scope.user.enabled = true;
|
||||
$scope.user = { enabled: true, attributes: {} }
|
||||
} else {
|
||||
if (!user.attributes) {
|
||||
user.attributes = {}
|
||||
}
|
||||
$scope.user = angular.copy(user);
|
||||
if(user.federationLink) {
|
||||
console.log("federationLink is not null");
|
||||
UserFederationInstances.get({realm : realm.realm, instance: user.federationLink}, function(link) {
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
<fieldset>
|
||||
<legend collapsed><span class="text">Contact Information</span> <span tooltip-placement="right" tooltip="Expand this section to configure user's contact information." class="fa fa-info-circle"></span></legend>
|
||||
<div class="form-group clearfix block">
|
||||
<label class="col-sm-2 control-label" for="street">Street</label>
|
||||
<div class="col-sm-6">
|
||||
<input ng-model="user.attributes.street" class="form-control" type="text" name="street" id="street" />
|
||||
</div>
|
||||
<span tooltip-placement="right" tooltip="Street address." class="fa fa-info-circle"></span>
|
||||
</div>
|
||||
<div class="form-group clearfix block">
|
||||
<label class="col-sm-2 control-label" for="locality">City or Locality</label>
|
||||
<div class="col-sm-6">
|
||||
<input ng-model="user.attributes.locality" class="form-control" type="text" name="locality" id="locality" />
|
||||
</div>
|
||||
<span tooltip-placement="right" tooltip="City or locality." class="fa fa-info-circle"></span>
|
||||
</div>
|
||||
<div class="form-group clearfix block">
|
||||
<label class="col-sm-2 control-label" for="region">State, Province, or Region</label>
|
||||
<div class="col-sm-6">
|
||||
<input ng-model="user.attributes.region" class="form-control" type="text" name="region" id="region" />
|
||||
</div>
|
||||
<span tooltip-placement="right" tooltip="State, province, prefecture, or region." class="fa fa-info-circle"></span>
|
||||
</div>
|
||||
<div class="form-group clearfix block">
|
||||
<label class="col-sm-2 control-label" for="postal_code">Zip or Postal code</label>
|
||||
<div class="col-sm-6">
|
||||
<input ng-model="user.attributes.postal_code" class="form-control" type="text" name="postal_code" id="postal_code" />
|
||||
</div>
|
||||
<span tooltip-placement="right" tooltip="Zip code or postal code." class="fa fa-info-circle"></span>
|
||||
</div>
|
||||
<div class="form-group clearfix block">
|
||||
<label class="col-sm-2 control-label" for="country">Country</label>
|
||||
<div class="col-sm-6">
|
||||
<input ng-model="user.attributes.country" class="form-control" type="text" name="country" id="country" />
|
||||
</div>
|
||||
<span tooltip-placement="right" tooltip="Country name." class="fa fa-info-circle"></span>
|
||||
</div>
|
||||
</fieldset>
|
|
@ -101,6 +101,7 @@
|
|||
<span tooltip-placement="right" tooltip="Require an action when the user logs in. 'Verify email' sends an email to the user to verify their email address. 'Update profile' requires user to enter in new personal information. 'Update password' requires user to enter in a new password. 'Configure TOTP' requires setup of a mobile password generator." class="fa fa-info-circle"></span>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div data-ng-include data-src="resourceUrl + '/partials/user-attribute-entry.html'"></div>
|
||||
<div class="pull-right form-actions" data-ng-show="create && access.manageUsers">
|
||||
<button kc-cancel data-ng-click="cancel()">Cancel</button>
|
||||
<button kc-save data-ng-show="changed">Save</button>
|
||||
|
|
|
@ -6,6 +6,11 @@ register=Register
|
|||
registerWith=Register with
|
||||
allRequired=All fields are required
|
||||
alreadyHaveAccount=Already have an account?
|
||||
street=Street
|
||||
locality=City or Locality
|
||||
region=State, Province, or Region
|
||||
postal_code=Zip or Postal code
|
||||
country=Country
|
||||
|
||||
poweredByKeycloak=Powered by Keycloak
|
||||
|
||||
|
|
|
@ -60,6 +60,53 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="user.attributes.street" class="${properties.kcLabelClass!}">${rb.street}</label>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-10 col-md-10">
|
||||
<input type="text" class="${properties.kcInputClass!}" id="user.attributes.street" name="user.attributes.street"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="user.attributes.locality" class="${properties.kcLabelClass!}">${rb.locality}</label>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-10 col-md-10">
|
||||
<input type="text" class="${properties.kcInputClass!}" id="user.attributes.locality" name="user.attributes.locality"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="user.attributes.region" class="${properties.kcLabelClass!}">${rb.region}</label>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-10 col-md-10">
|
||||
<input type="text" class="${properties.kcInputClass!}" id="user.attributes.region" name="user.attributes.region"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="user.attributes.postal_code" class="${properties.kcLabelClass!}">${rb.postal_code}</label>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-10 col-md-10">
|
||||
<input type="text" class="${properties.kcInputClass!}" id="user.attributes.postal_code" name="user.attributes.postal_code"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="${properties.kcLabelWrapperClass!}">
|
||||
<label for="user.attributes.country" class="${properties.kcLabelClass!}">${rb.country}</label>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-10 col-md-10">
|
||||
<input type="text" class="${properties.kcInputClass!}" id="user.attributes.country" name="user.attributes.country"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="${properties.kcFormGroupClass!}">
|
||||
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
|
||||
<div class="${properties.kcFormOptionsWrapperClass!}">
|
||||
|
|
|
@ -432,6 +432,8 @@ public class AccountService {
|
|||
|
||||
user.setEmail(formData.getFirst("email"));
|
||||
|
||||
AttributeFormDataProcessor.process(formData, realm, user);
|
||||
|
||||
event.event(EventType.UPDATE_PROFILE).client(auth.getClient()).user(auth.getUser()).success();
|
||||
|
||||
if (emailChanged) {
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package org.keycloak.services.resources;
|
||||
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
|
||||
import javax.ws.rs.core.MultivaluedMap;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class AttributeFormDataProcessor {
|
||||
/**
|
||||
* Looks for "user.attributes." keys in the form data and sets the appropriate UserModel.attribute from it.
|
||||
*
|
||||
* @param formData
|
||||
* @param realm
|
||||
* @param user
|
||||
*/
|
||||
public static void process(MultivaluedMap<String, String> formData, RealmModel realm, UserModel user) {
|
||||
for (String key : formData.keySet()) {
|
||||
if (!key.startsWith("user.attributes.")) continue;
|
||||
String attribute = key.substring("user.attributes.".length());
|
||||
user.setAttribute(attribute, formData.getFirst(key));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -507,6 +507,8 @@ public class LoginActionsService {
|
|||
}
|
||||
}
|
||||
|
||||
AttributeFormDataProcessor.process(formData, realm, user);
|
||||
|
||||
event.user(user).success();
|
||||
event.reset();
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@ public class AccountTest {
|
|||
});
|
||||
}
|
||||
|
||||
@Test @Ignore
|
||||
//@Test @Ignore
|
||||
public void runit() throws Exception {
|
||||
Thread.sleep(10000000);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue