Implement user "disabled" flag as an alternative to deleting the account
1 files added
12 files modified
| | |
| | | - Added FishEye hook script (pr-137) |
| | | - Added Redmine Fetch hook script (issue-359) |
| | | - Added Subgit hook contributed by TMate Software |
| | | - Added function to retain a user account but prohibit authentication. This is an alternative to deleting a user account. |
| | | dependencyChanges: |
| | | - updated to Jetty 8.1.13 |
| | | - updated to JGit 3.2.0 |
| | |
| | |
|
| | | private static final String ACCOUNTTYPE = "accountType";
|
| | |
|
| | | private static final String DISABLED = "disabled";
|
| | |
|
| | | private final File realmFile;
|
| | |
|
| | | private final Logger logger = LoggerFactory.getLogger(ConfigUserService.class);
|
| | |
| | | if (!StringUtils.isEmpty(model.countryCode)) {
|
| | | config.setString(USER, model.username, COUNTRYCODE, model.countryCode);
|
| | | }
|
| | | if (model.disabled) {
|
| | | config.setBoolean(USER, model.username, DISABLED, true);
|
| | | }
|
| | | if (model.getPreferences() != null) {
|
| | | if (!StringUtils.isEmpty(model.getPreferences().locale)) {
|
| | | config.setString(USER, model.username, LOCALE, model.getPreferences().locale);
|
| | |
| | | if (Constants.EXTERNAL_ACCOUNT.equals(user.password) && user.accountType.isLocal()) {
|
| | | user.accountType = AccountType.EXTERNAL;
|
| | | }
|
| | | user.disabled = config.getBoolean(USER, username, DISABLED, false);
|
| | | user.organizationalUnit = config.getString(USER, username, ORGANIZATIONALUNIT);
|
| | | user.organization = config.getString(USER, username, ORGANIZATION);
|
| | | user.locality = config.getString(USER, username, LOCALITY);
|
| | |
| | |
|
| | | private JCheckBox notFederatedCheckbox;
|
| | |
|
| | | private JCheckBox disabledCheckbox;
|
| | |
|
| | | private JTextField organizationalUnitField;
|
| | |
|
| | | private JTextField organizationField;
|
| | |
| | | notFederatedCheckbox = new JCheckBox(
|
| | | Translation.get("gb.excludeFromFederationDescription"),
|
| | | anUser.excludeFromFederation);
|
| | | disabledCheckbox = new JCheckBox(Translation.get("gb.disableUserDescription"), anUser.disabled);
|
| | |
|
| | | organizationalUnitField = new JTextField(anUser.organizationalUnit == null ? "" : anUser.organizationalUnit, 25);
|
| | | organizationField = new JTextField(anUser.organization == null ? "" : anUser.organization, 25);
|
| | |
| | | fieldsPanel.add(newFieldPanel(Translation.get("gb.canCreate"), canCreateCheckbox));
|
| | | fieldsPanel.add(newFieldPanel(Translation.get("gb.excludeFromFederation"),
|
| | | notFederatedCheckbox));
|
| | | fieldsPanel.add(newFieldPanel(Translation.get("gb.disableUser"), disabledCheckbox));
|
| | |
|
| | | JPanel attributesPanel = new JPanel(new GridLayout(0, 1, 5, 2));
|
| | | attributesPanel.add(newFieldPanel(Translation.get("gb.organizationalUnit") + " (OU)", organizationalUnitField));
|
| | |
| | | user.canFork = canForkCheckbox.isSelected();
|
| | | user.canCreate = canCreateCheckbox.isSelected();
|
| | | user.excludeFromFederation = notFederatedCheckbox.isSelected();
|
| | | user.disabled = disabledCheckbox.isSelected();
|
| | |
|
| | | user.organizationalUnit = organizationalUnitField.getText().trim();
|
| | | user.organization = organizationField.getText().trim();
|
| | |
| | | flagWicketSession(AuthenticationType.CONTAINER); |
| | | logger.debug(MessageFormat.format("{0} authenticated by servlet container principal from {1}", |
| | | user.username, httpRequest.getRemoteAddr())); |
| | | return user; |
| | | return validateAuthentication(user, AuthenticationType.CONTAINER); |
| | | } else if (settings.getBoolean(Keys.realm.container.autoCreateAccounts, false) |
| | | && !internalAccount) { |
| | | // auto-create user from an authenticated container principal |
| | |
| | | flagWicketSession(AuthenticationType.CONTAINER); |
| | | logger.debug(MessageFormat.format("{0} authenticated and created by servlet container principal from {1}", |
| | | user.username, httpRequest.getRemoteAddr())); |
| | | return user; |
| | | return validateAuthentication(user, AuthenticationType.CONTAINER); |
| | | } else if (!internalAccount) { |
| | | logger.warn(MessageFormat.format("Failed to find UserModel for {0}, attempted servlet container authentication from {1}", |
| | | principal.getName(), httpRequest.getRemoteAddr())); |
| | |
| | | flagWicketSession(AuthenticationType.CERTIFICATE); |
| | | logger.debug(MessageFormat.format("{0} authenticated by client certificate {1} from {2}", |
| | | user.username, metadata.serialNumber, httpRequest.getRemoteAddr())); |
| | | return user; |
| | | return validateAuthentication(user, AuthenticationType.CERTIFICATE); |
| | | } else { |
| | | logger.warn(MessageFormat.format("Failed to find UserModel for {0}, attempted client certificate ({1}) authentication from {2}", |
| | | model.username, metadata.serialNumber, httpRequest.getRemoteAddr())); |
| | |
| | | flagWicketSession(AuthenticationType.COOKIE); |
| | | logger.debug(MessageFormat.format("{0} authenticated by cookie from {1}", |
| | | user.username, httpRequest.getRemoteAddr())); |
| | | return user; |
| | | return validateAuthentication(user, AuthenticationType.COOKIE); |
| | | } |
| | | } |
| | | |
| | |
| | | flagWicketSession(AuthenticationType.CREDENTIALS); |
| | | logger.debug(MessageFormat.format("{0} authenticated by BASIC request header from {1}", |
| | | user.username, httpRequest.getRemoteAddr())); |
| | | return user; |
| | | return validateAuthentication(user, AuthenticationType.CREDENTIALS); |
| | | } else { |
| | | logger.warn(MessageFormat.format("Failed login attempt for {0}, invalid credentials from {1}", |
| | | username, httpRequest.getRemoteAddr())); |
| | |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * This method allows the authentication manager to reject authentication |
| | | * attempts. It is called after the username/secret have been verified to |
| | | * ensure that the authentication technique has been logged. |
| | | * |
| | | * @param user |
| | | * @return |
| | | */ |
| | | protected UserModel validateAuthentication(UserModel user, AuthenticationType type) { |
| | | if (user == null) { |
| | | return null; |
| | | } |
| | | if (user.disabled) { |
| | | // user has been disabled |
| | | logger.warn("Rejected {} authentication attempt by disabled account \"{}\"", |
| | | type, user.username); |
| | | return null; |
| | | } |
| | | return user; |
| | | } |
| | | |
| | | protected void flagWicketSession(AuthenticationType authenticationType) { |
| | |
| | | // plain-text password |
| | | returnedUser = user; |
| | | } |
| | | return returnedUser; |
| | | return validateAuthentication(returnedUser, AuthenticationType.CREDENTIALS); |
| | | } |
| | | |
| | | // try registered external authentication providers |
| | |
| | | if (user != null) { |
| | | // user authenticated |
| | | user.accountType = provider.getAccountType(); |
| | | return user; |
| | | return validateAuthentication(user, AuthenticationType.CREDENTIALS); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return user; |
| | | return validateAuthentication(user, AuthenticationType.CREDENTIALS); |
| | | } |
| | | |
| | | /** |
| | |
| | | public boolean canFork;
|
| | | public boolean canCreate;
|
| | | public boolean excludeFromFederation;
|
| | | public boolean disabled;
|
| | | // retained for backwards-compatibility with RPC clients
|
| | | @Deprecated
|
| | | public final Set<String> repositories = new HashSet<String>();
|
| | |
| | | gb.approve = approve |
| | | gb.hasNotReviewed = has not reviewed |
| | | gb.about = about |
| | | gb.ticketN = ticket #{0} |
| | | gb.ticketN = ticket #{0} |
| | | gb.disableUser = disable user |
| | | gb.disableUserDescription = prevent this account from authenticating |
| | |
| | | <tr><th><wicket:message key="gb.confirmPassword"></wicket:message></th><td class="edit"><input type="password" wicket:id="confirmPassword" size="30" tabindex="3" /></td></tr>
|
| | | <tr><th><wicket:message key="gb.displayName"></wicket:message></th><td class="edit"><input type="text" wicket:id="displayName" size="30" tabindex="4" /></td></tr>
|
| | | <tr><th><wicket:message key="gb.emailAddress"></wicket:message></th><td class="edit"><input type="text" wicket:id="emailAddress" size="30" tabindex="5" /></td></tr>
|
| | | <tr><th><wicket:message key="gb.canAdmin"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canAdmin" tabindex="6" /> <span class="help-inline"><wicket:message key="gb.canAdminDescription"></wicket:message></span></label></td></tr> |
| | | <tr><th><wicket:message key="gb.canCreate"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canCreate" tabindex="7" /> <span class="help-inline"><wicket:message key="gb.canCreateDescription"></wicket:message></span></label></td></tr> |
| | | <tr><th><wicket:message key="gb.canFork"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canFork" tabindex="8" /> <span class="help-inline"><wicket:message key="gb.canForkDescription"></wicket:message></span></label></td></tr> |
| | | <tr><th><wicket:message key="gb.canAdmin"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canAdmin" tabindex="6" /> <span class="help-inline"><wicket:message key="gb.canAdminDescription"></wicket:message></span></label></td></tr>
|
| | | <tr><th><wicket:message key="gb.canCreate"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canCreate" tabindex="7" /> <span class="help-inline"><wicket:message key="gb.canCreateDescription"></wicket:message></span></label></td></tr>
|
| | | <tr><th><wicket:message key="gb.canFork"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="canFork" tabindex="8" /> <span class="help-inline"><wicket:message key="gb.canForkDescription"></wicket:message></span></label></td></tr>
|
| | | <tr><th><wicket:message key="gb.excludeFromFederation"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="excludeFromFederation" tabindex="9" /> <span class="help-inline"><wicket:message key="gb.excludeFromFederationDescription"></wicket:message></span></label></td></tr>
|
| | | <tr><th><wicket:message key="gb.disableUser"></wicket:message></th><td class="edit"><label class="checkbox"><input type="checkbox" wicket:id="disabled" tabindex="10" /> <span class="help-inline"><wicket:message key="gb.disableUserDescription"></wicket:message></span></label></td></tr>
|
| | | </tbody>
|
| | | </table>
|
| | | </div>
|
| | |
| | | form.add(new CheckBox("canFork").setEnabled(app().settings().getBoolean(Keys.web.allowForking, true)));
|
| | | form.add(new CheckBox("canCreate"));
|
| | | form.add(new CheckBox("excludeFromFederation"));
|
| | | form.add(new CheckBox("disabled"));
|
| | |
|
| | | form.add(new RegistrantPermissionsPanel("repositories", RegistrantType.REPOSITORY, repos, permissions, getAccessPermissions()));
|
| | | form.add(teams.setEnabled(editTeams));
|
| | |
|
| | |
| | | // any changes to permissions or roles (issue-186)
|
| | | UserModel user = app().users().getUserModel(session.getUser().username);
|
| | |
|
| | | if (user.disabled) {
|
| | | // user was disabled during session
|
| | | HttpServletResponse response = ((WebResponse) getRequestCycle().getResponse())
|
| | | .getHttpServletResponse();
|
| | | app().authentication().logout(response, user);
|
| | | session.setUser(null);
|
| | | session.invalidateNow();
|
| | | return;
|
| | | }
|
| | |
|
| | | // validate cookie during session (issue-361)
|
| | | if (user != null && app().settings().getBoolean(Keys.web.allowCookieAuthentication, true)) {
|
| | | HttpServletRequest request = ((WebRequest) getRequestCycle().getRequest())
|
| | |
| | | @Override
|
| | | public void populateItem(final Item<UserModel> item) {
|
| | | final UserModel entry = item.getModelObject();
|
| | | LinkPanel editLink = new LinkPanel("username", "list", entry.username,
|
| | | String css = "list" + (entry.disabled ? "-strikethrough":"");
|
| | | LinkPanel editLink = new LinkPanel("username", css, entry.username,
|
| | | EditUserPage.class, WicketUtils.newUsernameParameter(entry.username));
|
| | | WicketUtils.setHtmlTooltip(editLink, getString("gb.edit") + " " + entry.getDisplayName());
|
| | | item.add(editLink);
|
| | |
| | | if (StringUtils.isEmpty(entry.displayName)) {
|
| | | item.add(new Label("displayName").setVisible(false));
|
| | | } else {
|
| | | editLink = new LinkPanel("displayName", "list", entry.getDisplayName(),
|
| | | editLink = new LinkPanel("displayName", css, entry.getDisplayName(),
|
| | | EditUserPage.class, WicketUtils.newUsernameParameter(entry.username));
|
| | | WicketUtils.setHtmlTooltip(editLink, getString("gb.edit") + " " + entry.getDisplayName());
|
| | | item.add(editLink);
|
| | |
| | | if (StringUtils.isEmpty(entry.emailAddress)) {
|
| | | item.add(new Label("emailAddress").setVisible(false));
|
| | | } else {
|
| | | editLink = new LinkPanel("emailAddress", "list", entry.emailAddress,
|
| | | editLink = new LinkPanel("emailAddress", css, entry.emailAddress,
|
| | | EditUserPage.class, WicketUtils.newUsernameParameter(entry.username));
|
| | | WicketUtils.setHtmlTooltip(editLink, getString("gb.edit") + " " + entry.getDisplayName());
|
| | | item.add(editLink);
|
| | |
| | | white-space: nowrap; |
| | | vertical-align: baseline; |
| | | } |
| | | |
| | |
|
| | | [class^="icon-"], [class*=" icon-"] i {
|
| | | /* override for a links that look like bootstrap buttons */
|
| | | vertical-align: text-bottom;
|
| | |
| | | color: inherit;
|
| | | }
|
| | |
|
| | | a.list-strikethrough {
|
| | | text-decoration: line-through;
|
| | | color: inherit;
|
| | | }
|
| | |
|
| | | a.list.subject {
|
| | | font-weight: bold;
|
| | | }
|
New file |
| | |
| | | /* |
| | | * Copyright 2013 gitblit.com. |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package com.gitblit.tests; |
| | | |
| | | import java.util.HashMap; |
| | | |
| | | import org.junit.Test; |
| | | |
| | | import com.gitblit.manager.AuthenticationManager; |
| | | import com.gitblit.manager.IAuthenticationManager; |
| | | import com.gitblit.manager.IUserManager; |
| | | import com.gitblit.manager.RuntimeManager; |
| | | import com.gitblit.manager.UserManager; |
| | | import com.gitblit.models.UserModel; |
| | | import com.gitblit.tests.mock.MemorySettings; |
| | | |
| | | /** |
| | | * Class for testing local authentication. |
| | | * |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | public class AuthenticationManagerTest extends GitblitUnitTest { |
| | | |
| | | IUserManager users; |
| | | |
| | | MemorySettings getSettings() { |
| | | return new MemorySettings(new HashMap<String, Object>()); |
| | | } |
| | | |
| | | IAuthenticationManager newAuthenticationManager() { |
| | | RuntimeManager runtime = new RuntimeManager(getSettings(), GitBlitSuite.BASEFOLDER).start(); |
| | | users = new UserManager(runtime).start(); |
| | | AuthenticationManager auth = new AuthenticationManager(runtime, users).start(); |
| | | return auth; |
| | | } |
| | | |
| | | @Test |
| | | public void testAuthenticate() throws Exception { |
| | | IAuthenticationManager auth = newAuthenticationManager(); |
| | | |
| | | UserModel user = new UserModel("sunnyjim"); |
| | | user.password = "password"; |
| | | users.updateUserModel(user); |
| | | |
| | | assertNotNull(auth.authenticate(user.username, user.password.toCharArray())); |
| | | user.disabled = true; |
| | | |
| | | users.updateUserModel(user); |
| | | assertNull(auth.authenticate(user.username, user.password.toCharArray())); |
| | | users.deleteUserModel(user); |
| | | } |
| | | } |
| | |
| | | GroovyScriptTest.class, LuceneExecutorTest.class, RepositoryModelTest.class,
|
| | | FanoutServiceTest.class, Issue0259Test.class, Issue0271Test.class, HtpasswdAuthenticationTest.class,
|
| | | ModelUtilsTest.class, JnaUtilsTest.class, LdapSyncServiceTest.class, FileTicketServiceTest.class, |
| | | BranchTicketServiceTest.class, RedisTicketServiceTest.class }) |
| | | BranchTicketServiceTest.class, RedisTicketServiceTest.class, AuthenticationManagerTest.class }) |
| | | public class GitBlitSuite {
|
| | |
|
| | | public static final File BASEFOLDER = new File("data");
|