@@ -45,6 +45,7 @@ | |||
<classpathentry kind="lib" path="ext/platform-3.5.0.jar" sourcepath="ext/src/platform-3.5.0.jar" /> | |||
<classpathentry kind="lib" path="ext/jna-3.5.0.jar" sourcepath="ext/src/jna-3.5.0.jar" /> | |||
<classpathentry kind="lib" path="ext/guava-13.0.1.jar" sourcepath="ext/src/guava-13.0.1.jar" /> | |||
<classpathentry kind="lib" path="ext/libpam4j-1.7.jar" sourcepath="ext/src/libpam4j-1.7.jar" /> | |||
<classpathentry kind="lib" path="ext/junit-4.11.jar" sourcepath="ext/src/junit-4.11.jar" /> | |||
<classpathentry kind="lib" path="ext/hamcrest-core-1.3.jar" sourcepath="ext/src/hamcrest-core-1.3.jar" /> | |||
<classpathentry kind="lib" path="ext/selenium-java-2.28.0.jar" sourcepath="ext/src/selenium-java-2.28.0.jar" /> |
@@ -150,6 +150,7 @@ dependencies: | |||
- compile 'com.force.api:force-partner-api:24.0.0' :war | |||
- compile 'org.freemarker:freemarker:2.3.19' :war | |||
- compile 'com.github.dblock.waffle:waffle-jna:1.5' :war | |||
- compile 'org.kohsuke:libpam4j:1.7' :war | |||
- test 'junit' | |||
# Dependencies for Selenium web page testing | |||
- test 'org.seleniumhq.selenium:selenium-java:${selenium.version}' @jar |
@@ -302,6 +302,7 @@ | |||
<class name="com.gitblit.RedmineUserService" /> | |||
<class name="com.gitblit.SalesforceUserService" /> | |||
<class name="com.gitblit.WindowsUserService" /> | |||
<class name="com.gitblit.PAMUserService" /> | |||
</mx:genjar> | |||
<!-- Build the WAR file --> | |||
@@ -421,6 +422,7 @@ | |||
<class name="com.gitblit.RedmineUserService" /> | |||
<class name="com.gitblit.SalesforceUserService" /> | |||
<class name="com.gitblit.WindowsUserService" /> | |||
<class name="com.gitblit.PAMUserService" /> | |||
</mx:genjar> | |||
<!-- Build Express Zip file --> |
@@ -468,6 +468,17 @@ | |||
</SOURCES> | |||
</library> | |||
</orderEntry> | |||
<orderEntry type="module-library"> | |||
<library name="libpam4j-1.7.jar"> | |||
<CLASSES> | |||
<root url="jar://$MODULE_DIR$/ext/libpam4j-1.7.jar!/" /> | |||
</CLASSES> | |||
<JAVADOC /> | |||
<SOURCES> | |||
<root url="jar://$MODULE_DIR$/ext/src/libpam4j-1.7.jar!/" /> | |||
</SOURCES> | |||
</library> | |||
</orderEntry> | |||
<orderEntry type="module-library" scope="TEST"> | |||
<library name="junit-4.11.jar"> | |||
<CLASSES> |
@@ -32,9 +32,12 @@ r18: { | |||
additions: | |||
- Added optional browser-side page caching using Last-Modified and Cache-Control for the dashboard, activity, project, and several repository pages | |||
- Added a GET_USER request type for the RPC mechanism (issue-275) | |||
- Added PAMUserService to authenticate against a local Linux/Unix/MacOSX server | |||
dependencyChanges: ~ | |||
settings: | |||
- { name: 'web.pageCacheExpires', defaultValue: 0 } | |||
- { name: 'realm.pam.backingUserService', defaultValue: 'users.conf' } | |||
- { name: 'realm.pam.serviceName', defaultValue: 'system-auth' } | |||
contributors: | |||
- Rainer Alföldi | |||
- Liyu Wang |
@@ -501,6 +501,7 @@ web.projectsFile = ${baseFolder}/projects.conf | |||
# com.gitblit.RedmineUserService | |||
# com.gitblit.SalesforceUserService | |||
# com.gitblit.WindowsUserService | |||
# com.gitblit.PAMUserService | |||
# | |||
# Any custom user service implementation must have a public default constructor. | |||
# | |||
@@ -1212,6 +1213,21 @@ realm.windows.allowGuests = false | |||
# SINCE 1.3.0 | |||
realm.windows.defaultDomain = | |||
# The PAMUserService must be backed by another user service for standard user | |||
# and team management. | |||
# default: users.conf | |||
# | |||
# RESTART REQUIRED | |||
# BASEFOLDER | |||
# SINCE 1.3.1 | |||
realm.pam.backingUserService = ${baseFolder}/users.conf | |||
# The PAM service name for authentication. | |||
# default: system-auth | |||
# | |||
# SINCE 1.3.1 | |||
realm.pam.serviceName = system-auth | |||
# The SalesforceUserService must be backed by another user service for standard user | |||
# and team management. | |||
# default: users.conf |
@@ -480,7 +480,7 @@ public class Constants { | |||
} | |||
public static enum AccountType { | |||
LOCAL, EXTERNAL, LDAP, REDMINE, SALESFORCE, WINDOWS; | |||
LOCAL, EXTERNAL, LDAP, REDMINE, SALESFORCE, WINDOWS, PAM; | |||
public boolean isLocal() { | |||
return this == LOCAL; |
@@ -0,0 +1,142 @@ | |||
/* | |||
* 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; | |||
} | |||
} |
@@ -37,6 +37,7 @@ | |||
- Redmine authentication | |||
- Salesforce.com authentication | |||
- Windows authentication | |||
- PAM authentication | |||
- Gravatar integration | |||
- Git-notes display support | |||
- Submodule support |
@@ -6,6 +6,7 @@ Gitblit supports additional authentication mechanisms aside from it's internal o | |||
* LDAP authentication | |||
* Windows authentication | |||
* PAM authentication | |||
* Redmine auhentication | |||
* Salesforce.com authentication | |||
* Servlet container authentication | |||
@@ -83,6 +84,13 @@ Windows authentication is based on the use of Waffle and JNA. It is known to wo | |||
realm.userService = com.gitblit.WindowsUserService | |||
realm.windows.defaultDomain = | |||
### PAM Authentication | |||
PAM authentication is based on the use of libpam4j and JNA. To use this service, your Gitblit server must be installed on a Linux/Unix/MacOSX machine and the user that Gitblit runs-as must have root permissions. | |||
realm.userService = com.gitblit.PAMUserService | |||
realm.pam.serviceName = system-auth | |||
### Redmine Authentication | |||
You may authenticate your users against a Redmine installation as long as your Redmine install has properly enabled [API authentication](http://www.redmine.org/projects/redmine/wiki/Rest_Api#Authentication). This user service only supports user authentication; it does not support team creation based on Redmine groups. Redmine administrators will also be Gitblit administrators. |
@@ -68,9 +68,10 @@ Administrators can create and manage all repositories, user accounts, and teams | |||
- Groovy push hook scripts | |||
- Pluggable user service mechanism | |||
- LDAP authentication with optional LDAP-controlled Team memberships | |||
- Redmine authentication | |||
- SalesForce.com authentication | |||
- Windows authentication | |||
- Redmine authentication | |||
- SalesForce.com authentication | |||
- Windows authentication | |||
- PAM authentication | |||
- Custom authentication, authorization, and user management | |||
- Rich RSS feeds | |||
- JSON-based RPC mechanism |