You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

EditUserPage.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. /*
  2. * Copyright 2011 gitblit.com.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.gitblit.wicket.pages;
  17. import java.text.MessageFormat;
  18. import java.util.ArrayList;
  19. import java.util.Collections;
  20. import java.util.Iterator;
  21. import java.util.List;
  22. import java.util.Locale;
  23. import com.gitblit.utils.PasswordHash;
  24. import org.apache.wicket.PageParameters;
  25. import org.apache.wicket.behavior.SimpleAttributeModifier;
  26. import org.apache.wicket.extensions.markup.html.form.palette.Palette;
  27. import org.apache.wicket.markup.html.form.Button;
  28. import org.apache.wicket.markup.html.form.CheckBox;
  29. import org.apache.wicket.markup.html.form.DropDownChoice;
  30. import org.apache.wicket.markup.html.form.Form;
  31. import org.apache.wicket.markup.html.form.TextField;
  32. import org.apache.wicket.model.CompoundPropertyModel;
  33. import org.apache.wicket.model.IModel;
  34. import org.apache.wicket.model.Model;
  35. import org.apache.wicket.model.util.CollectionModel;
  36. import org.apache.wicket.model.util.ListModel;
  37. import com.gitblit.Constants.RegistrantType;
  38. import com.gitblit.Constants.Role;
  39. import com.gitblit.GitBlitException;
  40. import com.gitblit.Keys;
  41. import com.gitblit.models.RegistrantAccessPermission;
  42. import com.gitblit.models.TeamModel;
  43. import com.gitblit.models.UserModel;
  44. import com.gitblit.utils.StringUtils;
  45. import com.gitblit.wicket.NonTrimmedPasswordTextField;
  46. import com.gitblit.wicket.RequiresAdminRole;
  47. import com.gitblit.wicket.StringChoiceRenderer;
  48. import com.gitblit.wicket.WicketUtils;
  49. import com.gitblit.wicket.panels.RegistrantPermissionsPanel;
  50. @RequiresAdminRole
  51. public class EditUserPage extends RootSubPage {
  52. private final boolean isCreate;
  53. public EditUserPage() {
  54. // create constructor
  55. super();
  56. isCreate = true;
  57. setupPage(new UserModel(""));
  58. setStatelessHint(false);
  59. setOutputMarkupId(true);
  60. }
  61. public EditUserPage(PageParameters params) {
  62. // edit constructor
  63. super(params);
  64. isCreate = false;
  65. String name = WicketUtils.getUsername(params);
  66. UserModel model = app().users().getUserModel(name);
  67. setupPage(model);
  68. setStatelessHint(false);
  69. setOutputMarkupId(true);
  70. }
  71. @Override
  72. protected boolean requiresPageMap() {
  73. return true;
  74. }
  75. @Override
  76. protected Class<? extends BasePage> getRootNavPageClass() {
  77. return UsersPage.class;
  78. }
  79. protected void setupPage(final UserModel userModel) {
  80. if (isCreate) {
  81. super.setupPage(getString("gb.newUser"), "");
  82. } else {
  83. super.setupPage(getString("gb.edit"), userModel.username);
  84. }
  85. final Model<String> confirmPassword = new Model<String>(
  86. StringUtils.isEmpty(userModel.password) ? "" : userModel.password);
  87. CompoundPropertyModel<UserModel> model = new CompoundPropertyModel<UserModel>(userModel);
  88. // build list of projects including all repositories wildcards
  89. List<String> repos = getAccessRestrictedRepositoryList(true, userModel);
  90. List<String> userTeams = new ArrayList<String>();
  91. for (TeamModel team : userModel.teams) {
  92. userTeams.add(team.name);
  93. }
  94. Collections.sort(userTeams);
  95. final String oldName = userModel.username;
  96. final List<RegistrantAccessPermission> permissions = app().repositories().getUserAccessPermissions(userModel);
  97. final Palette<String> teams = new Palette<String>("teams", new ListModel<String>(
  98. new ArrayList<String>(userTeams)), new CollectionModel<String>(app().users()
  99. .getAllTeamNames()), new StringChoiceRenderer(), 10, false);
  100. Locale locale = userModel.getPreferences().getLocale();
  101. List<Language> languages = UserPage.getLanguages();
  102. Language preferredLanguage = UserPage.getPreferredLanguage(locale, languages);
  103. final IModel<Language> language = Model.of(preferredLanguage);
  104. Form<UserModel> form = new Form<UserModel>("editForm", model) {
  105. private static final long serialVersionUID = 1L;
  106. /*
  107. * (non-Javadoc)
  108. *
  109. * @see org.apache.wicket.markup.html.form.Form#onSubmit()
  110. */
  111. @Override
  112. protected void onSubmit() {
  113. if (StringUtils.isEmpty(userModel.username)) {
  114. error(getString("gb.pleaseSetUsername"));
  115. return;
  116. }
  117. Language lang = language.getObject();
  118. if (lang != null) {
  119. userModel.getPreferences().setLocale(lang.code);
  120. }
  121. // force username to lower-case
  122. userModel.username = userModel.username.toLowerCase();
  123. String username = userModel.username;
  124. if (isCreate) {
  125. UserModel model = app().users().getUserModel(username);
  126. if (model != null) {
  127. error(MessageFormat.format(getString("gb.usernameUnavailable"), username));
  128. return;
  129. }
  130. }
  131. boolean rename = !StringUtils.isEmpty(oldName)
  132. && !oldName.equalsIgnoreCase(username);
  133. if (app().authentication().supportsCredentialChanges(userModel)) {
  134. if (!userModel.password.equals(confirmPassword.getObject())) {
  135. error(getString("gb.passwordsDoNotMatch"));
  136. return;
  137. }
  138. String password = userModel.password;
  139. if (!PasswordHash.isHashedEntry(password)) {
  140. // This is a plain text password.
  141. // Check length.
  142. int minLength = app().settings().getInteger(Keys.realm.minPasswordLength, 5);
  143. if (minLength < 4) {
  144. minLength = 4;
  145. }
  146. if (password.trim().length() < minLength) { // TODO: Why do we trim here, but not in EditUserDialog and ChangePasswordPage?
  147. error(MessageFormat.format(getString("gb.passwordTooShort"),
  148. minLength));
  149. return;
  150. }
  151. // change the cookie
  152. userModel.cookie = userModel.createCookie();
  153. // Optionally store the password MD5 digest.
  154. String type = app().settings().getString(Keys.realm.passwordStorage, PasswordHash.getDefaultType().name());
  155. PasswordHash pwdh = PasswordHash.instanceOf(type);
  156. if (pwdh != null) { // Hash the password
  157. userModel.password = pwdh.toHashedEntry(password, username);
  158. }
  159. } else if (rename
  160. && password.toUpperCase().startsWith(PasswordHash.Type.CMD5.name())) {
  161. error(getString("gb.combinedMd5Rename"));
  162. return;
  163. }
  164. }
  165. // update user permissions
  166. for (RegistrantAccessPermission repositoryPermission : permissions) {
  167. if (repositoryPermission.mutable) {
  168. userModel.setRepositoryPermission(repositoryPermission.registrant, repositoryPermission.permission);
  169. }
  170. }
  171. Iterator<String> selectedTeams = teams.getSelectedChoices();
  172. userModel.teams.clear();
  173. while (selectedTeams.hasNext()) {
  174. TeamModel team = app().users().getTeamModel(selectedTeams.next());
  175. if (team == null) {
  176. continue;
  177. }
  178. userModel.teams.add(team);
  179. }
  180. try {
  181. if (isCreate) {
  182. app().gitblit().addUser(userModel);
  183. } else {
  184. app().gitblit().reviseUser(oldName, userModel);
  185. }
  186. } catch (GitBlitException e) {
  187. error(e.getMessage());
  188. return;
  189. }
  190. setRedirect(false);
  191. if (isCreate) {
  192. // create another user
  193. info(MessageFormat.format(getString("gb.userCreated"),
  194. userModel.username));
  195. setResponsePage(EditUserPage.class);
  196. } else {
  197. // back to users page
  198. setResponsePage(UsersPage.class);
  199. }
  200. }
  201. };
  202. // do not let the browser pre-populate these fields
  203. form.add(new SimpleAttributeModifier("autocomplete", "off"));
  204. // not all user providers support manipulating username and password
  205. boolean editCredentials = app().authentication().supportsCredentialChanges(userModel);
  206. // not all user providers support manipulating display name
  207. boolean editDisplayName = app().authentication().supportsDisplayNameChanges(userModel);
  208. // not all user providers support manipulating email address
  209. boolean editEmailAddress = app().authentication().supportsEmailAddressChanges(userModel);
  210. // not all user providers support manipulating team memberships
  211. boolean editTeams = app().authentication().supportsTeamMembershipChanges(userModel);
  212. // not all user providers support manipulating the admin role
  213. boolean changeAdminRole = app().authentication().supportsRoleChanges(userModel, Role.ADMIN);
  214. // not all user providers support manipulating the create role
  215. boolean changeCreateRole = app().authentication().supportsRoleChanges(userModel, Role.CREATE);
  216. // not all user providers support manipulating the fork role
  217. boolean changeForkRole = app().authentication().supportsRoleChanges(userModel, Role.FORK);
  218. // field names reflective match UserModel fields
  219. form.add(new TextField<String>("username").setEnabled(editCredentials));
  220. NonTrimmedPasswordTextField passwordField = new NonTrimmedPasswordTextField("password");
  221. passwordField.setResetPassword(false);
  222. form.add(passwordField.setEnabled(editCredentials));
  223. NonTrimmedPasswordTextField confirmPasswordField = new NonTrimmedPasswordTextField("confirmPassword",
  224. confirmPassword);
  225. confirmPasswordField.setResetPassword(false);
  226. form.add(confirmPasswordField.setEnabled(editCredentials));
  227. form.add(new TextField<String>("displayName").setEnabled(editDisplayName));
  228. form.add(new TextField<String>("emailAddress").setEnabled(editEmailAddress));
  229. DropDownChoice<Language> choice = new DropDownChoice<Language>("language",language,languages );
  230. form.add( choice.setEnabled(languages.size()>0) );
  231. if (userModel.canAdmin() && !userModel.canAdmin) {
  232. // user inherits Admin permission
  233. // display a disabled-yet-checked checkbox
  234. form.add(new CheckBox("canAdmin", Model.of(true)).setEnabled(false));
  235. } else {
  236. form.add(new CheckBox("canAdmin").setEnabled(changeAdminRole));
  237. }
  238. if (userModel.canFork() && !userModel.canFork) {
  239. // user inherits Fork permission
  240. // display a disabled-yet-checked checkbox
  241. form.add(new CheckBox("canFork", Model.of(true)).setEnabled(false));
  242. } else {
  243. final boolean forkingAllowed = app().settings().getBoolean(Keys.web.allowForking, true);
  244. form.add(new CheckBox("canFork").setEnabled(forkingAllowed && changeForkRole));
  245. }
  246. if (userModel.canCreate() && !userModel.canCreate) {
  247. // user inherits Create permission
  248. // display a disabled-yet-checked checkbox
  249. form.add(new CheckBox("canCreate", Model.of(true)).setEnabled(false));
  250. } else {
  251. form.add(new CheckBox("canCreate").setEnabled(changeCreateRole));
  252. }
  253. form.add(new CheckBox("excludeFromFederation"));
  254. form.add(new CheckBox("disabled"));
  255. form.add(new RegistrantPermissionsPanel("repositories", RegistrantType.REPOSITORY, repos, permissions, getAccessPermissions()));
  256. form.add(teams.setEnabled(editTeams));
  257. form.add(new TextField<String>("organizationalUnit").setEnabled(editDisplayName));
  258. form.add(new TextField<String>("organization").setEnabled(editDisplayName));
  259. form.add(new TextField<String>("locality").setEnabled(editDisplayName));
  260. form.add(new TextField<String>("stateProvince").setEnabled(editDisplayName));
  261. form.add(new TextField<String>("countryCode").setEnabled(editDisplayName));
  262. form.add(new Button("save"));
  263. Button cancel = new Button("cancel") {
  264. private static final long serialVersionUID = 1L;
  265. @Override
  266. public void onSubmit() {
  267. setResponsePage(UsersPage.class);
  268. }
  269. };
  270. cancel.setDefaultFormProcessing(false);
  271. form.add(cancel);
  272. add(form);
  273. }
  274. }