| /* | |
| * 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; | |
| import java.io.File; | |
| import org.jvnet.libpam.PAM; | |
| import org.jvnet.libpam.PAMException; | |
| import org.jvnet.libpam.impl.CLibrary; | |
| import org.slf4j.Logger; | |
| import org.slf4j.LoggerFactory; | |
| import com.gitblit.Constants.AccountType; | |
| import com.gitblit.models.UserModel; | |
| import com.gitblit.utils.ArrayUtils; | |
| import com.gitblit.utils.StringUtils; | |
| /** | |
| * Implementation of a PAM user service for Linux/Unix/MacOSX. | |
| * | |
| * @author James Moger | |
| */ | |
| public class PAMUserService extends GitblitUserService { | |
| private final Logger logger = LoggerFactory.getLogger(PAMUserService.class); | |
| private IStoredSettings settings; | |
| public PAMUserService() { | |
| super(); | |
| } | |
| @Override | |
| public void setup(IStoredSettings settings) { | |
| this.settings = settings; | |
| String file = settings.getString(Keys.realm.pam.backingUserService, "${baseFolder}/users.conf"); | |
| File realmFile = GitBlit.getFileOrFolder(file); | |
| serviceImpl = createUserService(realmFile); | |
| logger.info("PAM User Service backed by " + serviceImpl.toString()); | |
| // Try to identify the passwd database | |
| String [] files = { "/etc/shadow", "/etc/master.passwd" }; | |
| File passwdFile = null; | |
| for (String name : files) { | |
| File f = new File(name); | |
| if (f.exists()) { | |
| passwdFile = f; | |
| break; | |
| } | |
| } | |
| if (passwdFile == null) { | |
| logger.error("PAM User Service could not find a passwd database!"); | |
| } else if (!passwdFile.canRead()) { | |
| logger.error("PAM User Service can not read passwd database {}! PAM authentications may fail!", passwdFile); | |
| } | |
| } | |
| @Override | |
| public boolean supportsCredentialChanges() { | |
| return false; | |
| } | |
| @Override | |
| public boolean supportsDisplayNameChanges() { | |
| return true; | |
| } | |
| @Override | |
| public boolean supportsEmailAddressChanges() { | |
| return true; | |
| } | |
| @Override | |
| public boolean supportsTeamMembershipChanges() { | |
| return true; | |
| } | |
| @Override | |
| protected AccountType getAccountType() { | |
| return AccountType.PAM; | |
| } | |
| @Override | |
| public UserModel authenticate(String username, char[] password) { | |
| if (isLocalAccount(username)) { | |
| // local account, bypass PAM authentication | |
| return super.authenticate(username, password); | |
| } | |
| if (CLibrary.libc.getpwnam(username) == null) { | |
| logger.warn("Can not get PAM passwd for " + username); | |
| return null; | |
| } | |
| PAM pam = null; | |
| try { | |
| String serviceName = settings.getString(Keys.realm.pam.serviceName, "system-auth"); | |
| pam = new PAM(serviceName); | |
| pam.authenticate(username, new String(password)); | |
| } catch (PAMException e) { | |
| logger.error(e.getMessage()); | |
| return null; | |
| } finally { | |
| pam.dispose(); | |
| } | |
| UserModel user = getUserModel(username); | |
| if (user == null) // create user object for new authenticated user | |
| user = new UserModel(username.toLowerCase()); | |
| // create a user cookie | |
| if (StringUtils.isEmpty(user.cookie) && !ArrayUtils.isEmpty(password)) { | |
| user.cookie = StringUtils.getSHA1(user.username + new String(password)); | |
| } | |
| // update user attributes from UnixUser | |
| user.accountType = getAccountType(); | |
| user.password = Constants.EXTERNAL_ACCOUNT; | |
| // TODO consider mapping PAM groups to teams | |
| // push the changes to the backing user service | |
| super.updateUserModel(user); | |
| return user; | |
| } | |
| } |