/* * Copyright 2011 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; import java.io.File; import java.io.IOException; import java.text.MessageFormat; import java.util.Collection; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.gitblit.Constants.AccountType; import com.gitblit.models.TeamModel; import com.gitblit.models.UserModel; import com.gitblit.utils.DeepCopier; import com.gitblit.utils.StringUtils; /** * This class wraps the default user service and is recommended as the starting * point for custom user service implementations. * * This does seem a little convoluted, but the idea is to allow IUserService to * evolve with new methods and implementations without breaking custom * authentication implementations. * * The most common implementation of a custom IUserService is to only override * authentication and then delegate all other functionality to one of Gitblit's * user services. This class optimizes that use-case. * * Extending GitblitUserService allows for authentication customization without * having to keep-up-with IUSerService API changes. * * @author James Moger * */ public class GitblitUserService implements IUserService { protected IUserService serviceImpl; private final Logger logger = LoggerFactory.getLogger(GitblitUserService.class); public GitblitUserService() { } @Override public void setup(IStoredSettings settings) { File realmFile = GitBlit.getFileOrFolder(Keys.realm.userService, "${baseFolder}/users.conf"); serviceImpl = createUserService(realmFile); logger.info("GUS delegating to " + serviceImpl.toString()); } protected IUserService createUserService(File realmFile) { IUserService service = null; if (realmFile.getName().toLowerCase().endsWith(".conf")) { // v0.8.0+ config-based realm file service = new ConfigUserService(realmFile); } assert service != null; if (!realmFile.exists()) { // Create the Administrator account for a new realm file try { realmFile.createNewFile(); } catch (IOException x) { logger.error(MessageFormat.format("COULD NOT CREATE REALM FILE {0}!", realmFile), x); } UserModel admin = new UserModel("admin"); admin.password = "admin"; admin.canAdmin = true; admin.excludeFromFederation = true; service.updateUserModel(admin); } return service; } @Override public String toString() { return getClass().getSimpleName(); } @Override public boolean supportsCredentialChanges() { return serviceImpl.supportsCredentialChanges(); } @Override public boolean supportsDisplayNameChanges() { return serviceImpl.supportsDisplayNameChanges(); } @Override public boolean supportsEmailAddressChanges() { return serviceImpl.supportsEmailAddressChanges(); } @Override public boolean supportsTeamMembershipChanges() { return serviceImpl.supportsTeamMembershipChanges(); } @Override public boolean supportsCookies() { return serviceImpl.supportsCookies(); } @Override public String getCookie(UserModel model) { return serviceImpl.getCookie(model); } @Override public UserModel authenticate(char[] cookie) { UserModel user = serviceImpl.authenticate(cookie); setAccountType(user); return user; } @Override public UserModel authenticate(String username, char[] password) { UserModel user = serviceImpl.authenticate(username, password); setAccountType(user); return user; } @Override public void logout(UserModel user) { serviceImpl.logout(user); } @Override public UserModel getUserModel(String username) { UserModel user = serviceImpl.getUserModel(username); setAccountType(user); return user; } @Override public boolean updateUserModel(UserModel model) { return serviceImpl.updateUserModel(model); } @Override public boolean updateUserModels(Collection models) { return serviceImpl.updateUserModels(models); } @Override public boolean updateUserModel(String username, UserModel model) { if (model.isLocalAccount() || supportsCredentialChanges()) { if (!model.isLocalAccount() && !supportsTeamMembershipChanges()) { // teams are externally controlled - copy from original model UserModel existingModel = getUserModel(username); model = DeepCopier.copy(model); model.teams.clear(); model.teams.addAll(existingModel.teams); } return serviceImpl.updateUserModel(username, model); } if (model.username.equals(username)) { // passwords are not persisted by the backing user service model.password = null; if (!model.isLocalAccount() && !supportsTeamMembershipChanges()) { // teams are externally controlled- copy from original model UserModel existingModel = getUserModel(username); model = DeepCopier.copy(model); model.teams.clear(); model.teams.addAll(existingModel.teams); } return serviceImpl.updateUserModel(username, model); } logger.error("Users can not be renamed!"); return false; } @Override public boolean deleteUserModel(UserModel model) { return serviceImpl.deleteUserModel(model); } @Override public boolean deleteUser(String username) { return serviceImpl.deleteUser(username); } @Override public List getAllUsernames() { return serviceImpl.getAllUsernames(); } @Override public List getAllUsers() { List users = serviceImpl.getAllUsers(); for (UserModel user : users) { setAccountType(user); } return users; } @Override public List getAllTeamNames() { return serviceImpl.getAllTeamNames(); } @Override public List getAllTeams() { return serviceImpl.getAllTeams(); } @Override public List getTeamnamesForRepositoryRole(String role) { return serviceImpl.getTeamnamesForRepositoryRole(role); } @Override @Deprecated public boolean setTeamnamesForRepositoryRole(String role, List teamnames) { return serviceImpl.setTeamnamesForRepositoryRole(role, teamnames); } @Override public TeamModel getTeamModel(String teamname) { return serviceImpl.getTeamModel(teamname); } @Override public boolean updateTeamModel(TeamModel model) { return serviceImpl.updateTeamModel(model); } @Override public boolean updateTeamModels(Collection models) { return serviceImpl.updateTeamModels(models); } @Override public boolean updateTeamModel(String teamname, TeamModel model) { if (!supportsTeamMembershipChanges()) { // teams are externally controlled - copy from original model TeamModel existingModel = getTeamModel(teamname); model = DeepCopier.copy(model); model.users.clear(); model.users.addAll(existingModel.users); } return serviceImpl.updateTeamModel(teamname, model); } @Override public boolean deleteTeamModel(TeamModel model) { return serviceImpl.deleteTeamModel(model); } @Override public boolean deleteTeam(String teamname) { return serviceImpl.deleteTeam(teamname); } @Override public List getUsernamesForRepositoryRole(String role) { return serviceImpl.getUsernamesForRepositoryRole(role); } @Override @Deprecated public boolean setUsernamesForRepositoryRole(String role, List usernames) { return serviceImpl.setUsernamesForRepositoryRole(role, usernames); } @Override public boolean renameRepositoryRole(String oldRole, String newRole) { return serviceImpl.renameRepositoryRole(oldRole, newRole); } @Override public boolean deleteRepositoryRole(String role) { return serviceImpl.deleteRepositoryRole(role); } protected boolean isLocalAccount(String username) { UserModel user = getUserModel(username); return user != null && user.isLocalAccount(); } protected void setAccountType(UserModel user) { if (user != null) { if (!StringUtils.isEmpty(user.password) && !Constants.EXTERNAL_ACCOUNT.equalsIgnoreCase(user.password) && !"StoredInLDAP".equalsIgnoreCase(user.password)) { user.accountType = AccountType.LOCAL; } else { user.accountType = getAccountType(); } } } protected AccountType getAccountType() { return AccountType.LOCAL; } }